fix(gamefont): Size glyph buffers to the glyph to prevent an overflow - #3268
fix(gamefont): Size glyph buffers to the glyph to prevent an overflow#3268tintinhamans wants to merge 2 commits into
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
PR Summary by QodoPrevent large glyphs from overflowing font buffers
AI Description
Diagram
High-Level Assessment
Files changed (3)
|
Code Review by Qodo
1. Oversized interface text disappears
|
|
| Filename | Overview |
|---|---|
| Core/Libraries/Source/WWVegas/WW3D2/render2dsentence.cpp | Allocates glyph buffers according to required capacity and explicitly releases their backing arrays. |
| Core/Libraries/Source/WWVegas/WW3D2/render2dsentence.h | Converts glyph buffers into value-stored descriptors containing allocation length and pixel pointer. |
| Core/GameEngine/Source/GameClient/GUI/GameFont.cpp | Clamps oversized font requests while preserving rejection of invalid non-positive sizes. |
| Core/GameEngine/Source/GameClient/GlobalLanguage.cpp | Applies the same maximum after resolution-based font scaling. |
| Core/GameEngine/Include/GameClient/GameFont.h | Defines the shared 512-point maximum used by font creation and scaling. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Request[Requested font size] --> Clamp[Clamp to 512 points]
Clamp --> Metrics[Measure glyph dimensions]
Metrics --> Required[Calculate required pixel count]
Required --> Check{Current buffer has room?}
Check -->|Yes| Write[Write glyph pixels]
Check -->|No| Allocate[Allocate max of default size and glyph size]
Allocate --> Write
Write --> Cache[Store stable pointer to glyph pixels]
Reviews (5): Last reviewed commit: "refactor(gamefont): Store glyph buffer d..." | Re-trigger Greptile
dbebfc4 to
33b6309
Compare
|
Can't we use At what font size did it overflow the original buffer? Was this leading to crashes? |
Theoretically somewhere around 130 to 150 point, can also be triggered by something like a custom map with
Each glyph caches a raw pointer into its slab |
| FontCharsBuffer* new_buffer = W3DNEW FontCharsBuffer; | ||
| // TheSuperHackers @fix arcticdolphin 07/09/2026 Grow the buffer to the glyph so a big one cannot overrun it. | ||
| const int length = (char_len > CHAR_BUFFER_LEN) ? char_len : CHAR_BUFFER_LEN; | ||
| FontCharsBuffer* new_buffer = W3DNEW FontCharsBuffer( length ); |
There was a problem hiding this comment.
This buffer now has 2 levels of indirection for every use case. Can we make this more optimal? Maybe BufferList should now carry FontCharsBuffer as value.
There was a problem hiding this comment.
Dropped the useless W3DMPO_CODE pooling and left BufferList as a pointer vector. Making FontCharsBuffer a value type is riskier than it looks DynamicVectorClass copies elements around internally when it grows.
There was a problem hiding this comment.
Making FontCharsBuffer a value type is riskier than it looks DynamicVectorClass copies elements around internally when it grows.
What is risky about it?
There was a problem hiding this comment.
Was worried about the destructor freeing buffers when the vector grows. Moved cleanup to FontCharsClass, so storing values works now.
|
Do this effect PR #3231 ? |
33b6309 to
eae556c
Compare
eae556c to
cb3ed94
Compare
| W3DMPO_CODE(FontCharsBuffer) | ||
| public: | ||
| uint16 Buffer[CHAR_BUFFER_LEN]; | ||
| FontCharsBuffer() : Length( 0 ), Buffer( 0 ) {} |
| // | ||
| StringClass Name; | ||
| DynamicVectorClass<FontCharsBuffer*> BufferList; | ||
| // TheSuperHackers @refactor arcticdolphin 08/09/2026 FontCharsClass owns the pixel arrays; descriptors are non-owning values. |
| } | ||
| FontCharsBuffer new_buffer; | ||
| new_buffer.Length = length; | ||
| new_buffer.Buffer = W3DNEWARRAY uint16[length]; |
There was a problem hiding this comment.
Maybe make this a constructor taking both arguments so that both are guaranteed set. Right now a caller could omit length.
|
|
||
| enum { CHAR_BUFFER_LEN = 32768 }; | ||
|
|
||
| // TheSuperHackers @fix arcticdolphin 07/09/2026 Buffer length matches the glyph so a large glyph cannot overrun it. |
| Int pointSize = REAL_TO_INT_FLOOR(theFontSize * adjustFactor); | ||
|
|
||
| // TheSuperHackers @fix arcticdolphin 07/09/2026 Keep the scaled size within what getFont can build. | ||
| if (pointSize > FONT_POINT_SIZE_MAX) |
There was a problem hiding this comment.
Is this clamp here necessary, considering font already clamps it anyway?
I assume it is needed so that callers work with the correct font sizes when they need it in calculations?
But I think it would be cleaner if callers then take the real font size from the GameFont class after it was created.
| { | ||
| FontCharsBuffer* new_buffer = W3DNEW FontCharsBuffer; | ||
| // TheSuperHackers @fix arcticdolphin 07/09/2026 Length may exceed CHAR_BUFFER_LEN to fit this glyph. | ||
| int length = CHAR_BUFFER_LEN; |
The glyph buffer was a fixed
uint16[32768].Store_GDI_Charwriteswidth * heightpixels with no bound check, so a big glyph writes past the end.A
pointSize > 100cap used to hide this, but it was removed in #3051 so 4K UI scalingcan use bigger fonts. A scaled font can now hit the overflow.
FontCharsBufferallocates its pixels and grows to fit the glyph.getFontclamps requests to 512 instead of rejecting them, so an oversizedrequest still returns a usable font rather than
nullptr(callers likeW3DDisplayString::setFontignore null and would show no text).adjustFontSizeclamps to the same max so the scaled size stays in range.A font size of about 460 is the most any real screen needs (a 48pt heading blown up 9.6x on an 8K display) so I think 512 is a safe value for now.