Skip to content

Commit 32cf8c7

Browse files
committed
Fix pointer aliasing bug in constant optimization
Variables modified through pointers incorrectly returned cached constant values instead of reloading from memory. This caused wrong results when a variable was initialized with a constant, had its address taken, and was modified through pointer indirection. Example that was broken: int b = 10; int *a = &b; a[0] = 5; return b; Previously returned 10 (cached), now correctly returns 5 (reloaded).
1 parent 3746f8d commit 32cf8c7

File tree

3 files changed

+42
-8
lines changed

3 files changed

+42
-8
lines changed

src/defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ struct var {
353353
int ptr_level;
354354
bool is_func;
355355
bool is_global;
356+
bool address_taken; /* true if variable address was taken (&var) */
356357
int array_size;
357358
int array_dim1, array_dim2; /* first/second dimension size for 2D arrays */
358359
int offset; /* offset from stack or frame, index 0 is reserved */

src/globals.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,14 @@ void add_insn(block_t *block,
10891089
else
10901090
n->str[0] = '\0';
10911091

1092+
/* Mark variables as address-taken to prevent incorrect constant
1093+
* optimization
1094+
*/
1095+
if ((op == OP_address_of || op == OP_global_address_of) && rs1) {
1096+
rs1->address_taken = true;
1097+
rs1->is_const = false; /* disable constant optimization */
1098+
}
1099+
10921100
if (!bb->insn_list.head)
10931101
bb->insn_list.head = n;
10941102
else

src/reg-alloc.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,18 +110,28 @@ int find_in_regs(var_t *var)
110110

111111
void load_var(basic_block_t *bb, var_t *var, int idx)
112112
{
113-
ph2_ir_t *ir = var->is_global ? bb_add_ph2_ir(bb, OP_global_load)
114-
: bb_add_ph2_ir(bb, OP_load);
115-
ir->src0 = var->offset;
113+
ph2_ir_t *ir;
114+
115+
/* Load constants directly, others from memory */
116+
if (var->is_const) {
117+
ir = bb_add_ph2_ir(bb, OP_load_constant);
118+
ir->src0 = var->init_val;
119+
} else {
120+
ir = var->is_global ? bb_add_ph2_ir(bb, OP_global_load)
121+
: bb_add_ph2_ir(bb, OP_load);
122+
ir->src0 = var->offset;
123+
}
124+
116125
ir->dest = idx;
117126
REGS[idx].var = var;
118127
REGS[idx].polluted = 0;
119128
}
120129

121130
int prepare_operand(basic_block_t *bb, var_t *var, int operand_0)
122131
{
132+
/* Force reload for address-taken variables (may be modified via pointer) */
123133
int i = find_in_regs(var);
124-
if (i > -1)
134+
if (i > -1 && !var->address_taken)
125135
return i;
126136

127137
for (i = 0; i < REG_CNT; i++) {
@@ -207,6 +217,16 @@ int prepare_dest(basic_block_t *bb, var_t *var, int operand_0, int operand_1)
207217

208218
void spill_alive(basic_block_t *bb, insn_t *insn)
209219
{
220+
/* Spill all locals on pointer writes (conservative aliasing handling) */
221+
if (insn && insn->opcode == OP_write) {
222+
for (int i = 0; i < REG_CNT; i++) {
223+
if (REGS[i].var && !REGS[i].var->is_global)
224+
spill_var(bb, REGS[i].var, i);
225+
}
226+
return;
227+
}
228+
229+
/* Standard spilling for non-pointer operations */
210230
for (int i = 0; i < REG_CNT; i++) {
211231
if (!REGS[i].var)
212232
continue;
@@ -471,9 +491,6 @@ void reg_alloc(void)
471491
break;
472492
case OP_load_constant:
473493
case OP_load_data_address:
474-
if (insn->rd->consumed == -1)
475-
break;
476-
477494
dest = prepare_dest(bb, insn->rd, -1, -1);
478495
ir = bb_add_ph2_ir(bb, insn->opcode);
479496
ir->src0 = insn->rd->init_val;
@@ -490,6 +507,12 @@ void reg_alloc(void)
490507
break;
491508
case OP_address_of:
492509
case OP_global_address_of:
510+
/* Mark variable as address-taken, disable constant
511+
* optimization
512+
*/
513+
insn->rs1->address_taken = true;
514+
insn->rs1->is_const = false;
515+
493516
/* make sure variable is on stack */
494517
if (!insn->rs1->offset) {
495518
insn->rs1->offset = bb->belong_to->stack_size;
@@ -500,6 +523,8 @@ void reg_alloc(void)
500523
ir = bb_add_ph2_ir(bb, OP_store);
501524
ir->src0 = i;
502525
ir->src1 = insn->rs1->offset;
526+
/* Clear stale register tracking */
527+
REGS[i].var = NULL;
503528
}
504529
}
505530

@@ -792,7 +817,7 @@ void dump_ph2_ir(void)
792817
printf("\t%%x%c = (%%x%c)", rd, rs1);
793818
break;
794819
case OP_write:
795-
printf("\t(%%x%c) = %%x%c", rs2, rs1);
820+
printf("\t(%%x%c) = %%x%c", rs1, rs2);
796821
break;
797822
case OP_address_of_func:
798823
printf("\t(%%x%c) = @%s", rs1, ph2_ir->func_name);

0 commit comments

Comments
 (0)