A few FCharacterList::GetCharacter() calls can cause use-after-free

In our case, FSlateFontMeasure::MeasureStringInternal triggered the use-after-free. Any code using this pattern will trigger it

  • Cache a const FCharacterEntry& from FCharacterList::GetCharacter()
  • Call another FCharacterList::GetCharacter() later in that function on a new (uncached) character
  • Deref the first const FCharacterEntry& can result in a use-after-free if the internal FCharacterList::MappedEntries is resized to accommodate the new cache size

I spotted a few risky cases in Engine code

  • FSlateFontMeasure::MeasureStringInternal described here
  • FCharacterList::GetKerning

As an experiment, I changed FCharacterList::MappedEntries to transact in unique ptrs to bypass the use-after-free and our crash disappeared when using -stompmalloc

TMap<TCHAR, TUniquePtr<FCharacterEntry>> MappedEntries;

I’m reluctant to use this code, since I don’t know the potential performance characteristics of introducing an allocation/level of indirection. Another, hacky, approach I considered was to reserve MappedEntries to the total number of possible characters in the font so it will never need to resize. That feels pretty magical, though.

Steps to Reproduce
Running with -stompmalloc, we caught this use-after-free from a call to FSlateEditableTextLayout::ForceRefreshTextLayout with the text input “BigNumber(_paramNumber.Value > 0 ? _paramNumber.Value : 100)” with a custom rich text marshaller that colors different identifiers/keywords in our proprietary scripting language. That bit is irrelevant, since you can see the use-after-frees in the code itself. See description below for where the code is risky.

Hello,

Thanks for reporting!

We noticed this issue on our side too, and a fix is available for FSlateFontMeasure::MeasureStringInternal, starting from UE 5.6.

You can also cherry pick it from here: https://github.com/EpicGames/UnrealEngine/commit/60985b210384def386241a35443467f314bf549e

However, looking at the usages of FCharacterList::GetCharacter() in the engine, it looks like there are potentially even more places that would need a fix, I’ll let you know when an additional changelist will be available.

Thanks,

Yohann