Skip to content

Fix UTF-8 buffer overflows from code-point string lengths - #522

Open
JarrettSJohnson wants to merge 2 commits into
masterfrom
fix-517-utf8-buffer-overflow
Open

JarrettSJohnson wants to merge 2 commits into
masterfrom
fix-517-utf8-buffer-overflow

Conversation

@JarrettSJohnson

@JarrettSJohnson JarrettSJohnson commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Fixes #517

Problem

On Python 3, PyString_Size maps to PyUnicode_GetLength, which counts code points. Three places used that count to size a char buffer and then copied the UTF-8 bytes into it. A CJK character is one code point but three bytes, so non-ASCII text overran the buffer:

  • PConvPyListToStringVLA (layer1/PConv.cpp): heap overflow. WizardRefresh uses it for the wizard prompt, which is the crash in the issue.
  • PopUpNew (layer4/PopUp.cpp): heap overflow. Menu label and command rows were sized by code points and filled with strcpy.
  • PConvPyListToStrVLAList (layer1/PConv.cpp): same sizing, but UtilNCopy truncates, so non-ASCII strings were cut short, possibly mid-character. Nothing in the tree calls it.

Fix

Size the buffers by UTF-8 byte length (SomeString::length() / strlen). The popup width still uses the code-point count, because the GLUT font draws one glyph per code point (FontGLUT.cpp). Non-ASCII labels don't make the popup wider.

Not covered: a str that can't be encoded as UTF-8 (e.g. a lone surrogate "\ud800") makes PyUnicode_AsUTF8 return null, and PConvPyListToStringVLA would dereference it. That bug already existed and is separate.

Testing

  • New test testing/tests/wizard/prompt.py: sets a long CJK wizard prompt and refreshes it. Without the fix it crashes (heap corruption abort); with the fix it passes. It uses a plain Wizard because the message wizard prints its text, which fails on the cp1252 console used by Windows CI.
  • The issue's case as a script (message wizard with CJK text, refreshed): segfaults every time without the fix (6 of 6 runs) and passes with it. An ASCII string of the same length passes on both.
  • Popup: a scripted click on a wizard panel menu with a long CJK label segfaults without the fix (3 of 3) and passes with it (3 of 3). I didn't add it as a test because it depends on injected mouse events and panel coordinates.
  • tests/wizard/ and tests/api/viewing.py via testing.py: 52 tests, no failures (6 skipped: no GUI / TODO).

🤖 Generated with Claude Code

JarrettSJohnson and others added 2 commits October 7, 2026 15:27
PyString_Size maps to PyUnicode_GetLength, which counts code points, but
these buffers are filled with UTF-8 bytes. Non-ASCII wizard prompts and
popup menu labels overflowed the heap.

Fixes #517

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The message wizard prints its text, which raises UnicodeEncodeError on
the cp1252 console used by Windows CI before the prompt conversion is
reached. Set the prompt on a plain Wizard instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread layer4/PopUp.cpp
str = PyString_AsString(elem);
cl = l;
l = strlen(str); /* buffer size in UTF-8 bytes */
cl = PyString_Size(elem); /* display width in characters */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe better to remove the legacy macros and to use PyUnicode_GetLength directly?

# define PyString_Size PyUnicode_GetLength
# define PyString_GET_SIZE PyUnicode_GetLength

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.

Heap buffer overflow in PConvPyListToStringVLA with non-ASCII wizard messages

2 participants