Skip to content

Commit 1f001e3

Browse files
authored
Fix crash on passing empty span to ImDrawList::AddText (#443)
* fix crash on passing empty span to ImDrawList::AddText * use Util.GetUtf8 in string arrays * support string ranges in generated code * update generated code in other projects * add missing overloads when using string ranges
1 parent 0693636 commit 1f001e3

File tree

17 files changed

+52123
-10942
lines changed

17 files changed

+52123
-10942
lines changed

src/CodeGenerator/Program.cs

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,12 @@ static void Main(string[] args)
373373
}
374374
if (exportedName.Contains("~")) { continue; }
375375
if (overload.Parameters.Any(tr => tr.Type.Contains('('))) { continue; } // TODO: Parse function pointer parameters.
376+
377+
if ((overload.FriendlyName == "GetID" || overload.FriendlyName == "PushID") && overload.Parameters.Length > 1)
378+
{
379+
// skip ImGui.Get/PushID(start, end) overloads as they would overlap with existing
380+
continue;
381+
}
376382

377383
bool hasVaList = false;
378384
for (int i = 0; i < overload.Parameters.Length; i++)
@@ -448,9 +454,22 @@ private static void EmitOverload(
448454
string selfName,
449455
string classPrefix)
450456
{
451-
if (overload.Parameters.Where(tr => tr.Name.EndsWith("_begin") || tr.Name.EndsWith("_end"))
452-
.Any(tr => !defaultValues.ContainsKey(tr.Name)))
453-
{
457+
var rangeParams = overload.Parameters.Where(tr =>
458+
tr.Name.EndsWith("_begin") ||
459+
tr.Name.EndsWith("_end")).ToArray();
460+
if (rangeParams.Any(tr => tr.Type != "char*"))
461+
{
462+
// only string supported for start/end. ImFont.IsGlyphRangeUnused is uint
463+
return;
464+
}
465+
if (rangeParams.Any(tr => tr.Name.EndsWith("_end") && defaultValues.ContainsKey(tr.Name)))
466+
{
467+
// we want overloads:
468+
// (something, text_start, text_end (deleted), after=default)
469+
// (something, text_start, text_end (deleted), after)
470+
471+
// we dont need (as it would be duplicate)
472+
// (something, text_start, text_end=default (deleted))
454473
return;
455474
}
456475

@@ -514,9 +533,20 @@ private static void EmitOverload(
514533
}
515534
else
516535
{
536+
if (tr.Name.EndsWith("_end"))
537+
{
538+
var startParamName = overload.Parameters[i-1].Name;
539+
var startNativeParamName = $"native_{startParamName}";
540+
marshalledParameters[i] = new MarshalledParameter(nativeTypeName, false, $"{startNativeParamName}+{startParamName}_byteCount", false);
541+
continue;
542+
}
543+
544+
var checkForNull = !hasDefault && !tr.Name.EndsWith("_begin");
545+
// for string _begin the pointer passed must be non-null, so we'll set up an empty string if needed
546+
517547
preCallLines.Add($"byte* {nativeArgName};");
518548
preCallLines.Add($"int {correctedIdentifier}_byteCount = 0;");
519-
if (!hasDefault)
549+
if (checkForNull)
520550
{
521551
preCallLines.Add($"if ({textToEncode} != null)");
522552
preCallLines.Add("{");
@@ -534,7 +564,7 @@ private static void EmitOverload(
534564
preCallLines.Add($" int {nativeArgName}_offset = Util.GetUtf8({textToEncode}, {nativeArgName}, {correctedIdentifier}_byteCount);");
535565
preCallLines.Add($" {nativeArgName}[{nativeArgName}_offset] = 0;");
536566

537-
if (!hasDefault)
567+
if (checkForNull)
538568
{
539569
preCallLines.Add("}");
540570
preCallLines.Add($"else {{ {nativeArgName} = null; }}");
@@ -576,12 +606,8 @@ private static void EmitOverload(
576606
preCallLines.Add($"for (int i = 0; i < {correctedIdentifier}.Length; i++)");
577607
preCallLines.Add("{");
578608
preCallLines.Add($" string s = {correctedIdentifier}[i];");
579-
preCallLines.Add($" fixed (char* sPtr = s)");
580-
preCallLines.Add(" {");
581-
preCallLines.Add($" offset += Encoding.UTF8.GetBytes(sPtr, s.Length, {nativeArgName}_data + offset, {correctedIdentifier}_byteCounts[i]);");
582-
preCallLines.Add($" {nativeArgName}_data[offset] = 0;");
583-
preCallLines.Add($" offset += 1;");
584-
preCallLines.Add(" }");
609+
preCallLines.Add($" offset += Util.GetUtf8(s, {nativeArgName}_data + offset, {correctedIdentifier}_byteCounts[i]);");
610+
preCallLines.Add($" {nativeArgName}_data[offset++] = 0;");
585611
preCallLines.Add("}");
586612

587613
preCallLines.Add($"byte** {nativeArgName} = stackalloc byte*[{correctedIdentifier}.Length];");

src/CodeGenerator/TypeInfo.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ public class TypeInfo
158158
{
159159
"igInputText",
160160
"igInputTextMultiline",
161-
"igCalcTextSize",
162161
"igInputTextWithHint"
163162
};
164163
}

src/ImGui.NET.SampleProgram/Program.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ private static unsafe void SubmitUI()
223223
ImGui.Text($"Hello, world {Random.Shared.Next(100)}!".AsSpan()); // Note that this call will STILL allocate memory due to string interpolation, but you can prevent that from happening by using an InterpolatedStringHandler.
224224
long allocBytesSpanEnd = GC.GetAllocatedBytesForCurrentThread() - allocBytesSpanStart;
225225
Console.WriteLine("GC (span): " + allocBytesSpanEnd);
226+
227+
ImGui.Text("Empty span:");
228+
ImGui.SameLine();
229+
ImGui.GetWindowDrawList().AddText(ImGui.GetCursorScreenPos(), uint.MaxValue, ReadOnlySpan<char>.Empty);
230+
ImGui.NewLine();
231+
ImGui.GetWindowDrawList().AddText(ImGui.GetCursorScreenPos(), uint.MaxValue, $"{ImGui.CalcTextSize("h")}");
232+
ImGui.NewLine();
233+
ImGui.TextUnformatted("TextUnformatted now passes end ptr but isn't cut off");
226234
}
227235
}
228236
}

src/ImGui.NET/Generated/ImDrawList.gen.cs

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,208 @@ public void AddRectFilledMultiColor(Vector2 p_min, Vector2 p_max, uint col_upr_l
298298
{
299299
ImGuiNative.ImDrawList_AddRectFilledMultiColor((ImDrawList*)(NativePtr), p_min, p_max, col_upr_left, col_upr_right, col_bot_right, col_bot_left);
300300
}
301+
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
302+
public void AddText(Vector2 pos, uint col, ReadOnlySpan<char> text_begin)
303+
{
304+
byte* native_text_begin;
305+
int text_begin_byteCount = 0;
306+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
307+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
308+
{
309+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
310+
}
311+
else
312+
{
313+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
314+
native_text_begin = native_text_begin_stackBytes;
315+
}
316+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
317+
native_text_begin[native_text_begin_offset] = 0;
318+
ImGuiNative.ImDrawList_AddText_Vec2((ImDrawList*)(NativePtr), pos, col, native_text_begin, native_text_begin+text_begin_byteCount);
319+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
320+
{
321+
Util.Free(native_text_begin);
322+
}
323+
}
324+
#endif
325+
public void AddText(Vector2 pos, uint col, string text_begin)
326+
{
327+
byte* native_text_begin;
328+
int text_begin_byteCount = 0;
329+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
330+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
331+
{
332+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
333+
}
334+
else
335+
{
336+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
337+
native_text_begin = native_text_begin_stackBytes;
338+
}
339+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
340+
native_text_begin[native_text_begin_offset] = 0;
341+
ImGuiNative.ImDrawList_AddText_Vec2((ImDrawList*)(NativePtr), pos, col, native_text_begin, native_text_begin+text_begin_byteCount);
342+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
343+
{
344+
Util.Free(native_text_begin);
345+
}
346+
}
347+
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
348+
public void AddText(ImFontPtr font, float font_size, Vector2 pos, uint col, ReadOnlySpan<char> text_begin)
349+
{
350+
ImFont* native_font = font.NativePtr;
351+
byte* native_text_begin;
352+
int text_begin_byteCount = 0;
353+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
354+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
355+
{
356+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
357+
}
358+
else
359+
{
360+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
361+
native_text_begin = native_text_begin_stackBytes;
362+
}
363+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
364+
native_text_begin[native_text_begin_offset] = 0;
365+
float wrap_width = 0.0f;
366+
Vector4* cpu_fine_clip_rect = null;
367+
ImGuiNative.ImDrawList_AddText_FontPtr((ImDrawList*)(NativePtr), native_font, font_size, pos, col, native_text_begin, native_text_begin+text_begin_byteCount, wrap_width, cpu_fine_clip_rect);
368+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
369+
{
370+
Util.Free(native_text_begin);
371+
}
372+
}
373+
#endif
374+
public void AddText(ImFontPtr font, float font_size, Vector2 pos, uint col, string text_begin)
375+
{
376+
ImFont* native_font = font.NativePtr;
377+
byte* native_text_begin;
378+
int text_begin_byteCount = 0;
379+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
380+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
381+
{
382+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
383+
}
384+
else
385+
{
386+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
387+
native_text_begin = native_text_begin_stackBytes;
388+
}
389+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
390+
native_text_begin[native_text_begin_offset] = 0;
391+
float wrap_width = 0.0f;
392+
Vector4* cpu_fine_clip_rect = null;
393+
ImGuiNative.ImDrawList_AddText_FontPtr((ImDrawList*)(NativePtr), native_font, font_size, pos, col, native_text_begin, native_text_begin+text_begin_byteCount, wrap_width, cpu_fine_clip_rect);
394+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
395+
{
396+
Util.Free(native_text_begin);
397+
}
398+
}
399+
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
400+
public void AddText(ImFontPtr font, float font_size, Vector2 pos, uint col, ReadOnlySpan<char> text_begin, float wrap_width)
401+
{
402+
ImFont* native_font = font.NativePtr;
403+
byte* native_text_begin;
404+
int text_begin_byteCount = 0;
405+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
406+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
407+
{
408+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
409+
}
410+
else
411+
{
412+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
413+
native_text_begin = native_text_begin_stackBytes;
414+
}
415+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
416+
native_text_begin[native_text_begin_offset] = 0;
417+
Vector4* cpu_fine_clip_rect = null;
418+
ImGuiNative.ImDrawList_AddText_FontPtr((ImDrawList*)(NativePtr), native_font, font_size, pos, col, native_text_begin, native_text_begin+text_begin_byteCount, wrap_width, cpu_fine_clip_rect);
419+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
420+
{
421+
Util.Free(native_text_begin);
422+
}
423+
}
424+
#endif
425+
public void AddText(ImFontPtr font, float font_size, Vector2 pos, uint col, string text_begin, float wrap_width)
426+
{
427+
ImFont* native_font = font.NativePtr;
428+
byte* native_text_begin;
429+
int text_begin_byteCount = 0;
430+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
431+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
432+
{
433+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
434+
}
435+
else
436+
{
437+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
438+
native_text_begin = native_text_begin_stackBytes;
439+
}
440+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
441+
native_text_begin[native_text_begin_offset] = 0;
442+
Vector4* cpu_fine_clip_rect = null;
443+
ImGuiNative.ImDrawList_AddText_FontPtr((ImDrawList*)(NativePtr), native_font, font_size, pos, col, native_text_begin, native_text_begin+text_begin_byteCount, wrap_width, cpu_fine_clip_rect);
444+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
445+
{
446+
Util.Free(native_text_begin);
447+
}
448+
}
449+
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
450+
public void AddText(ImFontPtr font, float font_size, Vector2 pos, uint col, ReadOnlySpan<char> text_begin, float wrap_width, ref Vector4 cpu_fine_clip_rect)
451+
{
452+
ImFont* native_font = font.NativePtr;
453+
byte* native_text_begin;
454+
int text_begin_byteCount = 0;
455+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
456+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
457+
{
458+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
459+
}
460+
else
461+
{
462+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
463+
native_text_begin = native_text_begin_stackBytes;
464+
}
465+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
466+
native_text_begin[native_text_begin_offset] = 0;
467+
fixed (Vector4* native_cpu_fine_clip_rect = &cpu_fine_clip_rect)
468+
{
469+
ImGuiNative.ImDrawList_AddText_FontPtr((ImDrawList*)(NativePtr), native_font, font_size, pos, col, native_text_begin, native_text_begin+text_begin_byteCount, wrap_width, native_cpu_fine_clip_rect);
470+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
471+
{
472+
Util.Free(native_text_begin);
473+
}
474+
}
475+
}
476+
#endif
477+
public void AddText(ImFontPtr font, float font_size, Vector2 pos, uint col, string text_begin, float wrap_width, ref Vector4 cpu_fine_clip_rect)
478+
{
479+
ImFont* native_font = font.NativePtr;
480+
byte* native_text_begin;
481+
int text_begin_byteCount = 0;
482+
text_begin_byteCount = Encoding.UTF8.GetByteCount(text_begin);
483+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
484+
{
485+
native_text_begin = Util.Allocate(text_begin_byteCount + 1);
486+
}
487+
else
488+
{
489+
byte* native_text_begin_stackBytes = stackalloc byte[text_begin_byteCount + 1];
490+
native_text_begin = native_text_begin_stackBytes;
491+
}
492+
int native_text_begin_offset = Util.GetUtf8(text_begin, native_text_begin, text_begin_byteCount);
493+
native_text_begin[native_text_begin_offset] = 0;
494+
fixed (Vector4* native_cpu_fine_clip_rect = &cpu_fine_clip_rect)
495+
{
496+
ImGuiNative.ImDrawList_AddText_FontPtr((ImDrawList*)(NativePtr), native_font, font_size, pos, col, native_text_begin, native_text_begin+text_begin_byteCount, wrap_width, native_cpu_fine_clip_rect);
497+
if (text_begin_byteCount > Util.StackAllocationSizeLimit)
498+
{
499+
Util.Free(native_text_begin);
500+
}
501+
}
502+
}
301503
public void AddTriangle(Vector2 p1, Vector2 p2, Vector2 p3, uint col)
302504
{
303505
float thickness = 1.0f;

0 commit comments

Comments
 (0)