Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nametabletest.cpp: fix out-of-bounds access on endianness conversion #74

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

trofi
Copy link

@trofi trofi commented Oct 24, 2022

Initially observed as a nametabletest test failre on today's gcc-13. -fsanitize=undefined detected off-by-one error accessing one element past NameRecord array:

$ ./tests/nametabletest/nametabletest
tests/nametabletest/nametabletest.cpp:142:79: runtime error: index 5 out of bounds for type 'NameRecord [5]'
...
tests/nametabletest/nametabletest.cpp:142:79: runtime error: index 7 out of bounds for type 'NameRecord [7]'
...

This happens because test record are slightly inconsistent: when name array has N entries N+1 is specified as count, and local toBigEndian helper uses this count to iterate over local array.

The rest of code (like NameTable::getLanguageId) seems to assume that table count is off-by-one.

The change fixes test failure on this week's gcc-13.

Initially observed as a `nametabletest` test failre on today's `gcc-13`.
`-fsanitize=undefined` detected off-by-one error accessing one element
past NameRecord array:

    $ ./tests/nametabletest/nametabletest
    tests/nametabletest/nametabletest.cpp:142:79: runtime error: index 5 out of bounds for type 'NameRecord [5]'
    ...
    tests/nametabletest/nametabletest.cpp:142:79: runtime error: index 7 out of bounds for type 'NameRecord [7]'
    ...

This happens because test record are slightly inconsistent:
when name array has N entries N+1 is specified as count, and local
`toBigEndian` helper uses this count to iterate over local array.

The rest of code (like `NameTable::getLanguageId`) seems to assume that
table count is off-by-one.

The change fixes test failure on this week's `gcc-13`.
Copy link
Contributor

@tim-eves tim-eves left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for spotting this bug. Looking into this further the real source of the bug is the use of sizeof(TtfUtil::Sfnt::FontNames) in calculating the nameheader count values initialised into testA and testBdeclarations at the start of the file. The underlying structure (FontName) includes a C++ spec compliant version of a flexible member array at the end, but due to C++ this cannot be 0, so it is 1 (these structures are designed for memory mapped reading of TTF files, rather than generation and writing). Several compilers permit 0 length arrays in that position, but that is due a compiler specific language extension, and we're trying to keep code like this as spec compliant as possible. That is where the +1 is coming from.

We do however include a non-entry for that first record embedded in the struct FontName , which the code in NameTable::getLanguageId() does process thus the +1 count is correct there. But as you identified we don't processs entries after that first one in the testcase and therefore the code in toBigEndian requires require the adjusted value.

@tim-eves
Copy link
Contributor

tim-eves commented Oct 25, 2022

@trofi This lead down quite the rabbit hole as it turns out nametabletest needs a bit of attention in places. It seems the test "worked" without your fix and started failing for the ksw-MM and mnw-MM language ID test cases with it. Your fix is undoubtedly a good fix, for an actual bug, but it seems the overrun you identified was silently byte swapping NameTestB::m_langTagCount into the correct byte order. This was supposed to be done in toBigEndian1(...), but that function wasn't being called at all. Once your fix is applied it uncovers this other bug. I'll commit a fix for both (and a couple of other discovered during fixing these), credit you in the commit and then close the PR with a comment once the fix is in the default branch.

@trofi trofi mentioned this pull request May 29, 2023
12 tasks
trofi added a commit to trofi/nixpkgs that referenced this pull request May 29, 2023
Without the change the test fails on gcc-13 as:

    $ ./tests/nametabletest/nametabletest
    tests/nametabletest/nametabletest.cpp:142:79: runtime error: index 5 out of bounds for type 'NameRecord [5]'
    ...
    tests/nametabletest/nametabletest.cpp:142:79: runtime error: index 7 out of bounds for type 'NameRecord [7]'
    ...

In silnrsi/graphite#74 upstream agrees it's a
problem in the test (and possibly the library). Let's disable the test
itself until upstream fixes it completely.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants