Skip to content

Instantly share code, notes, and snippets.

@siraben
Last active May 12, 2026 05:01
Show Gist options
  • Select an option

  • Save siraben/53a6ad67cbf20c021dff8f1044c75353 to your computer and use it in GitHub Desktop.

Select an option

Save siraben/53a6ad67cbf20c021dff8f1044c75353 to your computer and use it in GitHub Desktop.
m2-planet segfault
diff --git a/cc_core.c b/cc_core.c
index 1890595..cddb43b 100644
--- a/cc_core.c
+++ b/cc_core.c
@@ -273,13 +273,16 @@ void function_call(struct token_list* s, int is_function_pointer)
emit_push(REGISTER_BASE, "Protect the old base pointer");
emit_push(REGISTER_LOCALS, "Protect the old locals pointer");
- emit_move(REGISTER_TEMP, REGISTER_STACK, "Copy new base pointer");
-
+ /* Spill the function pointer to the stack instead of a register.
+ * On x86 REGISTER_TEMP2 is EDX, which is implicitly written by mul
+ * (used to scale array subscripts) when evaluating arguments. */
if(is_function_pointer)
{
- emit_move(REGISTER_TEMP2, REGISTER_ZERO, "Save function pointer address");
+ emit_push(REGISTER_ZERO, "Save function pointer on stack");
}
+ emit_move(REGISTER_TEMP, REGISTER_STACK, "Copy new base pointer");
+
int passed = 0;
while(global_token->s[0] != ')')
{
@@ -305,7 +308,8 @@ void function_call(struct token_list* s, int is_function_pointer)
if(TRUE == is_function_pointer)
{
- emit_move(REGISTER_ZERO, REGISTER_TEMP2, "Restore function pointer");
+ emit_load_relative_to_register(REGISTER_ZERO, REGISTER_TEMP, 0, "Address of saved function pointer");
+ emit_dereference(REGISTER_ZERO, "Restore function pointer from stack");
if(Architecture & ARCH_FAMILY_KNIGHT)
{
@@ -372,6 +376,11 @@ void function_call(struct token_list* s, int is_function_pointer)
emit_move(REGISTER_STACK, REGISTER_BASE, "Clean up function arguments");
}
+ if(is_function_pointer)
+ {
+ emit_pop(REGISTER_ONE, "Discard saved function pointer slot");
+ }
+
emit_pop(REGISTER_LOCALS, "Restore old locals pointer");
emit_pop(REGISTER_BASE, "Restore old base pointer");
if((AARCH64 == Architecture) || (RISCV64 == Architecture) || (RISCV32 == Architecture))
/* Minimal reproducer for the M2-Planet 1.13.x indirect-call bug.
* Exits 0 patched, segfaults unpatched. */
typedef unsigned (*FUNCTION)(unsigned);
unsigned table[1];
/* Array subscript emits `mul_ecx`, which clobbers EDX. */
unsigned get(unsigned i) { return table[i]; }
unsigned sink(unsigned x) { return x; }
int main()
{
FUNCTION fp = sink;
fp(get(0));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment