[tex-k] Phantom ligature bug in tftopl

James Fennell james at jpfennell.com
Mon Mar 18 04:09:23 CET 2024


I have found a bug in the tftopl program. I searched around but couldn’t find a preexisting report.

The effect of the bug is that tftopl will sometimes reject a valid .tfm file, incorrectly claiming that the file’s lig/kern program contains an infinite ligature loop. This can happen even if the .tfm file only contains kern instructions - i.e., no ligatures at all.

I have created 2 minimal examples. The first example is a .tfm file with only kerns (.tfm here [1], .pl here [2]). This example generates an “unconditional stop command address is too big” warning from tftopl, but this is a red herring. The second example is a 100% valid .tftm file with no warnings (.tfm here [3], .pl here [4]). In both cases just by looking at the output from tftopl you can see that tftopl is doing something wrong. When tftopl finds an infinite loop it still prints the apparently erroneous lig/kern program. In both cases by inspecting the .pl output we can see that there are no loops at all (especially easy in the kerns case!).

# Cause

In order to describe the cause, I need to briefly recap the format of lig/kern instructions in .tfm files. This is described in detail in section 13 of tftopl. Given the bytes for one instruction (b0, b1, b2, b3) there are 3 possible cases:

If b0<=128 and b2>=128, it is a kern instruction
If b0<=128 and b2<128, it is a ligature instruction.
If b0>128 it is an unconditional stop. (Note that in the kind of .tfm files produced by, say, pltotf, this instruction is not used for stopping, but rather as a mechanism for providing larger entry points for the lig/kern program.)

This bug concerns unconditional stops. There are multiple places in Knuth’s code where the instruction is first checked to be an unconditional stop before lig/kern logic runs. For example, in TeX section 909 the lig/kern logic only runs if b0<=128 (the conditional appears as “skip_byte(q) <= stop_flag”) [5]. Likewise in tftopl section 74, the lig/kern validation is skipped if “tfm[k]>stop_flag” [6].

The bug I’m reporting here is in the infinite loop checking code in tftopl. The bug is that this code forgets to check for the unconditional stop case. Instead, it interprets the unconditional stop as a kern or lig instruction, depending on the value of b2. This "phantom ligature" instruction may cause an infinite loop, and then tftopl will incorrectly fail.

# Fix

I believe there is a simple fix, though I haven’t verified it. In the hash_input routine (section 92) we need to exit early if b0>128. In the notation of the change files, we want something like this:

@x
begin if hash_ptr=hash_size then goto 30;
@y
begin if hash_ptr=hash_size then goto 30;
begin if tfm[k] >= stop_flag then goto 30;
@z

# Impact

I think this is a low impact bug because .tfm files produced by pltotf and other pieces of software don’t seem to hit it. I have tested all ~100k .tfm files in CTAN, and none of them have this bug.

I discovered it while working on a re-implementation of tftopl. I have a fuzzing setup that generates “random” .tfm files and verifies my re-implementation matches the original. This setup results in lots of weird edge cases in tftopl being hit, and this is one of them.

[1] https://github.com/jamespfennell/texcraft/blob/e89b74617808fa35b7dadb4efe4483415756ceec/crates/tfm/bin/tests/data/originals/phantom-ligature-bug-minimal-repro-1.tfm
[2] https://github.com/jamespfennell/texcraft/blob/e89b74617808fa35b7dadb4efe4483415756ceec/crates/tfm/bin/tests/data/originals/phantom-ligature-bug-minimal-repro-2.plst
[3] 
https://github.com/jamespfennell/texcraft/blob/main/crates/tfm/bin/tests/data/originals/phantom-ligature-bug-minimal-repro-2.tfm
[4] https://github.com/jamespfennell/texcraft/blob/main/crates/tfm/bin/tests/data/originals/phantom-ligature-bug-minimal-repro-2.plst
[5] https://github.com/TeX-Live/texlive-source/blob/f1b12d7a20aaad9200cc4948ff481ffa90648c34/texk/web2c/tex.web#L17866
[6] https://github.com/TeX-Live/texlive-source/blob/f1b12d7a20aaad9200cc4948ff481ffa90648c34/texk/web2c/tftopl.web#L1176
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://tug.org/pipermail/tex-k/attachments/20240317/f6b84e73/attachment.htm>


More information about the tex-k mailing list.