Skip to content

Commit 58cb1fe

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 58cb1fe

File tree

3 files changed

+43
-8
lines changed

3 files changed

+43
-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: 34 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,17 @@ 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+
}
227+
return;
228+
}
229+
230+
/* Standard spilling for non-pointer operations */
210231
for (int i = 0; i < REG_CNT; i++) {
211232
if (!REGS[i].var)
212233
continue;
@@ -471,9 +492,6 @@ void reg_alloc(void)
471492
break;
472493
case OP_load_constant:
473494
case OP_load_data_address:
474-
if (insn->rd->consumed == -1)
475-
break;
476-
477495
dest = prepare_dest(bb, insn->rd, -1, -1);
478496
ir = bb_add_ph2_ir(bb, insn->opcode);
479497
ir->src0 = insn->rd->init_val;
@@ -490,6 +508,12 @@ void reg_alloc(void)
490508
break;
491509
case OP_address_of:
492510
case OP_global_address_of:
511+
/* Mark variable as address-taken, disable constant
512+
* optimization
513+
*/
514+
insn->rs1->address_taken = true;
515+
insn->rs1->is_const = false;
516+
493517
/* make sure variable is on stack */
494518
if (!insn->rs1->offset) {
495519
insn->rs1->offset = bb->belong_to->stack_size;
@@ -500,6 +524,8 @@ void reg_alloc(void)
500524
ir = bb_add_ph2_ir(bb, OP_store);
501525
ir->src0 = i;
502526
ir->src1 = insn->rs1->offset;
527+
/* Clear stale register tracking */
528+
REGS[i].var = NULL;
503529
}
504530
}
505531

@@ -792,7 +818,7 @@ void dump_ph2_ir(void)
792818
printf("\t%%x%c = (%%x%c)", rd, rs1);
793819
break;
794820
case OP_write:
795-
printf("\t(%%x%c) = %%x%c", rs2, rs1);
821+
printf("\t(%%x%c) = %%x%c", rs1, rs2);
796822
break;
797823
case OP_address_of_func:
798824
printf("\t(%%x%c) = @%s", rs1, ph2_ir->func_name);

0 commit comments

Comments
 (0)