TMPro.TMP_FontAsset:AddSynthesizedCharacter causes crash when calling FontEngine:GetGlyphIndex

Hey, after updating to TMPro 2.1.4 on unity 2019.4.21f1 a large number of players of our game are experiencing a native crash coming from TMPro when one of our game objects gets enabled. I’m trying to figure out how I could possibly debug this to fix it

I notice that the FontEngine documentation does not reference the GetGlyphIndex function, but does have a TryGetGlyphIndex which makes me think that GetGlyphIndex can fail?

Any help would be appreciated, truncated call stack below :slight_smile:

0x00007FFCAE19FAD8 (UnityPlayer) UnityMain
0x00007FFCAE19CF78 (UnityPlayer) UnityMain
0x00007FFCAE1B66E7 (UnityPlayer) UnityMain
0x000001F21CCC285A (Mono JIT Code) (wrapper managed-to-native) UnityEngine.TextCore.LowLevel.FontEngine:GetGlyphIndex (uint)
0x000001F21CCC23F3 (Mono JIT Code) TMPro.TMP_FontAsset:AddSynthesizedCharacter (uint,bool)
0x000001F21CCC1A83 (Mono JIT Code) TMPro.TMP_FontAsset:AddSynthesizedCharactersAndFaceMetrics ()
0x000001F1FF03E8EB (Mono JIT Code) TMPro.TMP_FontAsset:ReadFontAssetDefinition ()
0x000001F1FF03E83B (Mono JIT Code) TMPro.TMP_FontAsset:get_characterLookupTable ()
0x000001F1FF03D66B (Mono JIT Code) TMPro.TextMeshProUGUI:LoadFontAsset ()
0x000001F1FF03C71F (Mono JIT Code) TMPro.TextMeshProUGUI:Awake ()
0x000001F161BDBA50 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007FFCAFC5DAD0 (mono-2.0-bdwgc) mono_get_runtime_build_info
0x00007FFCAFBE2932 (mono-2.0-bdwgc) mono_perfcounters_init
0x00007FFCAFBEB98F (mono-2.0-bdwgc) mono_runtime_invoke
0x00007FFCADC4A8AD (UnityPlayer) UnityMain
0x00007FFCADC47C43 (UnityPlayer) UnityMain
0x00007FFCADC47D0E (UnityPlayer) UnityMain
0x00007FFCADC71325 (UnityPlayer) UnityMain
0x00007FFCADC30B10 (UnityPlayer) UnityMain
0x00007FFCADC3019D (UnityPlayer) UnityMain
0x00007FFCADC3046C (UnityPlayer) UnityMain
0x00007FFCADC8484B (UnityPlayer) UnityMain
0x00007FFCAD9194A2 (UnityPlayer) UnityMain
0x00007FFCAD91CF40 (UnityPlayer) UnityMain
0x00007FFCADCBE3E7 (UnityPlayer) UnityMain
0x000001F160FED849 (Mono JIT Code) (wrapper managed-to-native) UnityEngine.GameObject:SetActive (UnityEngine.GameObject,bool)
1 Like

Are you able to reproduce the behavior on your end?

If so, any chance you could submit a bug report with project for me to look at or provide me with some repro to look at?

EDIT: If you are unable to submit a bug report or provide me with access to the project, you can always try to make the following change around line 725 in the TMP_FontAsset.cs file.

if (m_AtlasPopulationMode == AtlasPopulationMode.Dynamic)
{
    if (FontEngine.LoadFontFace(sourceFontFile, m_FaceInfo.pointSize) != FontEngineError.Success)
    {
        Debug.LogWarning("Unable to load font face for [" + sourceFontFile.name + "].");
        return;
    }
}

If you then get a log warning, it would indicate some issue loading the font face and possibly some issue with the font object.

P.S. If this crash only occurs in a build, you will most likely need to make this change in the Global Package Cache to make it persistent so we can figure out if the issue is font object related.

Thanks for the response, I’ll try to create a project which mimics the issue later this week (I cant distribute the project which is experiencing the issue)

Ill also make that change later this week to see if I get the warning

Anything you can provide will be much appreciated as I am not sure what would cause the crash specifically in GetGlyphIndex.

Do you unload resources somewhere in your code? Perhaps the font object used by this font asset gets unloaded which leads to this issue.

Just been going through the changes we made between releases and we added a call to Resources.UnloadUnusedAssets()… I imagine that’s probably actually what the cause of the issue is :confused:

No clue how that functions with referenced Font assets

This is what I suspected.

The reason this issue is happening now is the result of recent changes I made to reduce to memory overhead when using Font objects. In previous releases, the FontEngine would use GetFontData() on the font object which would return a copy of a byte[ ] that contains the entire font file. Given this was a copy, the FontEngine would cache it resulting in the overall memory overhead being 3X the size of the font file. With the change, the font object returns a reference to the font data so that we only get 1x of memory overhead but as we are seeing now, if this font object is unloaded, the FontEngine ends up using re-allocated memory.

What surprises me is Resources.UnloadUnusedAssets() unloading the font data although this font is referenced by the font asset where as such it should not unload it.

This new piece of information does give me something to look at so again thanks for sharing.

1 Like

Essentially, Players connect to a lobby, then load into an online match within a different scene and server.
They play their game out, and when they return to the Lobby we call Resources.UnloadUnusedAssets().

When they go into the next game, the first object they load which has a TMP pro asset on seems to have a chance of failing, because it not a 100% repro. These game objects are loaded from an addressable package which is probably useful info.

Tomorrow, Ill do a build with the call to Resources.UnloadUnusedAssets() and one without to test

Maybe as a result of Addressable being Async we end up with the font asset trying to access the font object before it was reloaded.

By the way, I did add a new API to the FontEngine in UnityEngine.TextCore.LowLevel

/// <summary>
/// Unloads all currently loaded font faces and removes them from the cache.
/// </summary>
/// <returns>A value of zero (0) if the font faces were successfully unloaded and removed from the cache.</returns>
public static FontEngineError UnloadAllFontFaces()

Assuming this is not an Async issue, calling FontEngine.UnloadAllFontFaces() right after Resources.UnloadUnusedAssets() might do the trick. This would force the FontEngine to re-fetch the font data from the font object.

Calling UnloadAllFontFaces() after the call to Resources.UnloadUnusedAssets() causes it to not crash when we load in more prefabs with TMPro text on, however loading a couple of the assets in succession causes the new ones to not render. So for now, my fix will be to remove my call to UnloadUnusedAssets()

I had a shot at making a small test project and was unable to do so. These assets that are loading in are years old by this point, and recreating it just didn’t yield the same results.

Now that we know the issue is related to unloading of resources, I’ll take a closer look into this. More specifically, I would like to understand why the font data of a font object which is referenced by a font asset is getting flushed. This might be a separate bug / unexpected behavior.

Besides the above, calling UnloadAllFontFaces() only clears the FontEngine font face cache which means the next time a character needs to be added to a font asset, the font face will have to be loaded from the font file again instead of from the cache. This has an impact on performance but should not affect anything already contained in the font asset. So I would like to figure out why this is resulting in some of the text objects not rendering correctly.

Hi Stephan,

I think we have a similar problem. But it appears in the editor. After changing the code, we click on Play, then the editor closes with the following error:

Received signal SIGSEGV
Stack trace:
0x00007ff738ad0d15 (Unity) tt_cmap12_char_index
0x00007ff738ae8eb7 (Unity) UNITY_FT_Get_Char_Index
0x00007ff736b7849a (Unity) FontEngine_CUSTOM_GetGlyphIndex
0x000001d531da2ce7 (Mono JIT Code) (wrapper managed-to-native) UnityEngine.TextCore.LowLevel.FontEngine:GetGlyphIndex (uint)
0x000001d531da2873 (Mono JIT Code) [TMP_FontAsset.cs:794] TMPro.TMP_FontAsset:AddSynthesizedCharacter (uint,bool)
0x000001d531da1da3 (Mono JIT Code) [TMP_FontAsset.cs:734] TMPro.TMP_FontAsset:AddSynthesizedCharactersAndFaceMetrics ()
0x000001d531d9ee6b (Mono JIT Code) [TMP_FontAsset.cs:578] TMPro.TMP_FontAsset:ReadFontAssetDefinition ()
0x000001d531d9ed6b (Mono JIT Code) [TMP_FontAsset.cs:556] TMPro.TMP_FontAsset:OnValidate ()
0x000001d531bc8860 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007ffd04b9e480 (mono-2.0-bdwgc) [mini-runtime.c:2812] mono_jit_runtime_invoke
0x00007ffd04b22902 (mono-2.0-bdwgc) [object.c:2921] do_runtime_invoke
0x00007ffd04b2b95f (mono-2.0-bdwgc) [object.c:2968] mono_runtime_invoke
0x00007ff7362baa34 (Unity) scripting_method_invoke
0x00007ff7362b33b5 (Unity) ScriptingInvocation::Invoke
0x00007ff7362b37ce (Unity) ScriptingInvocation::InvokeChecked
0x00007ff736330306 (Unity) SerializableManagedRef::CallMethod
0x00007ff736276e0d (Unity) MonoBehaviour::CheckConsistency
0x00007ff736275623 (Unity) MonoBehaviour::AwakeAfterRestoreFromBackup
0x00007ff73632fdd2 (Unity) SerializableManagedRefsUtilities::AwakeInstancesAfterBackupRestoration
0x00007ff736278314 (Unity) MonoManager::EndReloadAssembly
0x00007ff73627efe9 (Unity) MonoManager::ReloadAssembly
0x00007ff737622a71 (Unity) ReloadAllUsedAssemblies
0x00007ff7375f7dec (Unity) EditorSceneManager::RestoreSceneBackups
0x00007ff736fa320a (Unity) PlayerLoopController::EnterPlayMode
0x00007ff736fb8b2d (Unity) PlayerLoopController::SetIsPlaying
0x00007ff736fbb894 (Unity) Application::TickTimer
0x00007ff737923bb1 (Unity) MainMessageLoop
0x00007ff737927bf1 (Unity) WinMain
0x00007ff73979e0d6 (Unity) __scrt_common_main_seh
0x00007ffd6ec97034 (KERNEL32) BaseThreadInitThunk
0x00007ffd6fa22651 (ntdll) RtlUserThreadStart

This happens very often and makes it difficult to work :frowning:

1 Like

Are you able to reproduce this issue?

If so, any chance you could submit a bug report with project?

Unfortunately, we can’t repeat on a test project.
The problem goes away if we replace “Atlas popuplation mode” from Dynamic to Static in our project. But we need Dynamic mode.

This issue would occur when a font face was previously loaded from a Font object where this font object (more specifically the font data which is a byte array of the font file) is destroyed / deallocated somehow.

Similar to the other user, are you using Resources.UnloadUnusedAssets() or creating new font assets at runtime or loading some of these resources from an Asset Bundle or Addressables? Can you think of anything that would result in the font used by one of those font assets to be destroyed?

Do all these font assets have a reference to their source font?

See if making the following changes in the TMP_FontAsset.cs file resolves the issue.

6995003--826316--upload_2021-3-31_14-5-38.png

You will need to make the changes in the Global Package Cache\packages\com.unity.textmeshpro@1.5.4\Scripts\Runtime\TMP_FontAsset.cs file in order to make these changes persistent.

If you are using Unity 2019.4 then the package location will be com.unity.textmeshpro@2.1.4. For Unity 2020 or newer, it will be com.unity.textmeshpro@3.0.4

Note that I am still unable to reproduce the issue on my end but the above change should prevent calls to FontEngine.GetGlyphIndex when unable to successfully loading the requested font face.

1 Like

I get the same issue, crash every build or so… and yes I am using addressable
Will see if I can make the change
Unity 2021.1.1f1 (was doing the same on 2020.2) and TMP 3.0.4

Please submit a bug report with project if you can as I am still unable to reproduce this issue.

I have a rough idea of the cause but need to be able to reproduce it to properly resolve it.

It seem to improve it a lot for me…
Can’t log a bug report, project too big and it always fail while uploading, but if you want I can send you a link in pm to download. Just PM me

A link via PM would be great along with description / steps to reproduce the crash.

Ok will send you that…

1 Like