Skip to content

Commit 0fe401c

Browse files
committed
gfx/drivers/d3d9hlsl: NULL-check realloc in d3d9_hlsl_convert_macro_loops
Six realloc sites inside d3d9_hlsl_convert_macro_loops had no NULL check at all, just while (opos + N >= cap) { cap *= 2; out = (char*)realloc(out, cap); } memcpy(out + opos, ...); On OOM realloc returns NULL, the self-assign overwrites the only pointer to the old buffer (leaking it), and the very next line memcpys into NULL+opos - a segfault crash during Cg-style HLSL shader preprocessing. This function rewrites macro-unrolled loops in Cg shaders into HLSL [loop] form. It runs during shader-preset compilation, so every slang preset load that contains a qualifying macro (pattern: single-param function-like #define called N times with monotonically increasing integer arguments, N >= 4) hits this code path. Shader presets are user-provided and can be arbitrary size; a memory-tight system loading a big CRT-Royale- style preset at the wrong moment will crash here rather than fail gracefully. The other five callers inside the function (lines ~5749, 5760, 5772, 5786, 5795, 5803 pre-patch) all had the same bug. All six are fixed by switching to the realloc-into-tmp idiom: while (opos + N >= cap) { char *tmp; cap *= 2; if (!(tmp = (char*)realloc(out, cap))) { free(out); return NULL; } out = tmp; } This also plugs the self-assign leak that the pre-patch form would have triggered on OOM - since we free(out) on the failure path, the old buffer is reclaimed before we return NULL. Thread-safety: unchanged. Shader compilation runs on whichever thread loads the preset; d3d9_hlsl_convert_macro_loops does not touch any shared state beyond the const-source argument. Reachability: every Cg-style macro-expanded shader preset load on the D3D9-HLSL backend. The worst of the crash modes (writes past end of buffer on OOM) has been latent for as long as this preprocessing pass has been in tree. Scope: this commit only fixes the six sites in d3d9_hlsl_convert_macro_loops. The surrounding 8200-line file has ~13 more realloc-assign-self patterns in other HLSL-fixup functions (d3d9_hlsl_preprocess_includes, d3d9_hlsl_add_struct_ semantics, d3d9_hlsl_decompose_struct_samplers, d3d9_hlsl_fixup_cg_source, and the d3d9_hlsl_buf_append helper) that have the same leak-on-OOM pattern but do NULL-check after the realloc so they don't crash - just leak and return NULL. Those are worth fixing too but are a separate follow-up; this commit focuses on the six crash sites.
1 parent eebab97 commit 0fe401c

1 file changed

Lines changed: 42 additions & 6 deletions

File tree

gfx/drivers/d3d9hlsl.c

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5746,7 +5746,13 @@ static char *d3d9_hlsl_convert_macro_loops(const char *source)
57465746
|| macro_define_start[comment_len-1] == '\r'))
57475747
comment_len--;
57485748
while (opos + dll + comment_len + 10 >= cap)
5749-
{ cap *= 2; out = (char*)realloc(out, cap); }
5749+
{
5750+
char *tmp;
5751+
cap *= 2;
5752+
if (!(tmp = (char*)realloc(out, cap)))
5753+
{ free(out); return NULL; }
5754+
out = tmp;
5755+
}
57505756
memcpy(out + opos, dl, dll); opos += dll;
57515757
memcpy(out + opos, macro_define_start, comment_len);
57525758
opos += comment_len;
@@ -5757,7 +5763,13 @@ static char *d3d9_hlsl_convert_macro_loops(const char *source)
57575763
{
57585764
size_t mid = (size_t)(seq_start - macro_define_end);
57595765
while (opos + mid + 1 >= cap)
5760-
{ cap *= 2; out = (char*)realloc(out, cap); }
5766+
{
5767+
char *tmp;
5768+
cap *= 2;
5769+
if (!(tmp = (char*)realloc(out, cap)))
5770+
{ free(out); return NULL; }
5771+
out = tmp;
5772+
}
57615773
memcpy(out + opos, macro_define_end, mid);
57625774
opos += mid;
57635775
}
@@ -5769,7 +5781,13 @@ static char *d3d9_hlsl_convert_macro_loops(const char *source)
57695781
"[loop] for (int %s = 0; %s <= %d; %s++) {\n",
57705782
macro_param, macro_param, max_seq, macro_param);
57715783
while (opos + lh_len + 1 >= cap)
5772-
{ cap *= 2; out = (char*)realloc(out, cap); }
5784+
{
5785+
char *tmp;
5786+
cap *= 2;
5787+
if (!(tmp = (char*)realloc(out, cap)))
5788+
{ free(out); return NULL; }
5789+
out = tmp;
5790+
}
57735791
memcpy(out + opos, loop_header, lh_len);
57745792
opos += lh_len;
57755793
}
@@ -5783,7 +5801,13 @@ static char *d3d9_hlsl_convert_macro_loops(const char *source)
57835801
&& bp_src[1] == '\n')
57845802
{ bp_src += 2; continue; }
57855803
while (opos + 2 >= cap)
5786-
{ cap *= 2; out = (char*)realloc(out, cap); }
5804+
{
5805+
char *tmp;
5806+
cap *= 2;
5807+
if (!(tmp = (char*)realloc(out, cap)))
5808+
{ free(out); return NULL; }
5809+
out = tmp;
5810+
}
57875811
out[opos++] = *bp_src++;
57885812
}
57895813
}
@@ -5792,15 +5816,27 @@ static char *d3d9_hlsl_convert_macro_loops(const char *source)
57925816
{
57935817
const char *cl = "\n}\n";
57945818
while (opos + 4 >= cap)
5795-
{ cap *= 2; out = (char*)realloc(out, cap); }
5819+
{
5820+
char *tmp;
5821+
cap *= 2;
5822+
if (!(tmp = (char*)realloc(out, cap)))
5823+
{ free(out); return NULL; }
5824+
out = tmp;
5825+
}
57965826
memcpy(out + opos, cl, 3); opos += 3;
57975827
}
57985828

57995829
/* Copy everything after the macro call run */
58005830
{
58015831
size_t tail = src_len_full - (size_t)(seq_end_ptr - source);
58025832
while (opos + tail + 1 >= cap)
5803-
{ cap *= 2; out = (char*)realloc(out, cap); }
5833+
{
5834+
char *tmp;
5835+
cap *= 2;
5836+
if (!(tmp = (char*)realloc(out, cap)))
5837+
{ free(out); return NULL; }
5838+
out = tmp;
5839+
}
58045840
memcpy(out + opos, seq_end_ptr, tail);
58055841
opos += tail;
58065842
}

0 commit comments

Comments
 (0)