Skip to content

Commit 5c1c4ad

Browse files
committed
Fix typedef pointer arithmetic and array ops
This commit fixes multiple issues with typedef pointer handling: 1. Remove incorrect pointer level inheritance in read_full_var_decl() - Previously caused double indirection bugs with typedef pointers - Variables now maintain separate pointer levels from their types 2. Implement proper pointer arithmetic for typedef pointers - Add scaling for binary addition/subtraction (p+n, p-n, n+p) - Fix increment/decrement operators (++p, p++, --p, p--) - Calculate element size based on base type (int=4, char=1, etc.) 3. Enable array indexing for typedef pointers - Recognize typedef pointers in square bracket operations - Properly calculate element sizes for array access
1 parent 1aaad7e commit 5c1c4ad

File tree

2 files changed

+485
-12
lines changed

2 files changed

+485
-12
lines changed

src/parser.c

Lines changed: 279 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ var_t *truncate_unchecked(block_t *block,
281281
var_t *resize_var(block_t *block, basic_block_t **bb, var_t *from, var_t *to)
282282
{
283283
bool is_from_ptr = from->ptr_level || from->array_size,
284-
is_to_ptr = to->ptr_level || to->array_size;
284+
is_to_ptr = to->ptr_level || to->array_size ||
285+
(to->type && to->type->ptr_level > 0);
285286

286287
if (is_from_ptr && is_to_ptr)
287288
return from;
@@ -1291,10 +1292,6 @@ void read_full_var_decl(var_t *vd, bool anon, bool is_param)
12911292

12921293
vd->type = type;
12931294

1294-
/* Inherit pointer level from typedef */
1295-
if (type->ptr_level > 0)
1296-
vd->ptr_level = type->ptr_level;
1297-
12981295
read_inner_var_decl(vd, anon, is_param);
12991296
}
13001297

@@ -1569,8 +1566,28 @@ void handle_single_dereference(block_t *parent, basic_block_t **bb)
15691566
vd = require_deref_var(parent, var->type, var->ptr_level);
15701567
if (lvalue.ptr_level > 1)
15711568
sz = PTR_SIZE;
1572-
else
1573-
sz = lvalue.type->size;
1569+
else {
1570+
/* For typedef pointers, get the size of the pointed-to type */
1571+
if (lvalue.type && lvalue.type->ptr_level > 0) {
1572+
/* This is a typedef pointer */
1573+
switch (lvalue.type->base_type) {
1574+
case TYPE_char:
1575+
sz = TY_char->size;
1576+
break;
1577+
case TYPE_int:
1578+
sz = TY_int->size;
1579+
break;
1580+
case TYPE_void:
1581+
sz = 1;
1582+
break;
1583+
default:
1584+
sz = lvalue.type->size;
1585+
break;
1586+
}
1587+
} else {
1588+
sz = lvalue.type->size;
1589+
}
1590+
}
15741591
gen_name_to(vd->var_name);
15751592
opstack_push(vd);
15761593
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
@@ -1628,8 +1645,29 @@ void handle_multiple_dereference(block_t *parent, basic_block_t **bb)
16281645
lvalue.ptr_level > i ? lvalue.ptr_level - i - 1 : 0);
16291646
if (lvalue.ptr_level > i + 1)
16301647
sz = PTR_SIZE;
1631-
else
1632-
sz = lvalue.type->size;
1648+
else {
1649+
/* For typedef pointers, get the size of the pointed-to type */
1650+
if (lvalue.type && lvalue.type->ptr_level > 0 &&
1651+
i == deref_count - 1) {
1652+
/* This is a typedef pointer on the final dereference */
1653+
switch (lvalue.type->base_type) {
1654+
case TYPE_char:
1655+
sz = TY_char->size;
1656+
break;
1657+
case TYPE_int:
1658+
sz = TY_int->size;
1659+
break;
1660+
case TYPE_void:
1661+
sz = 1;
1662+
break;
1663+
default:
1664+
sz = lvalue.type->size;
1665+
break;
1666+
}
1667+
} else {
1668+
sz = lvalue.type->size;
1669+
}
1670+
}
16331671
gen_name_to(vd->var_name);
16341672
opstack_push(vd);
16351673
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
@@ -2197,6 +2235,99 @@ void read_expr(block_t *parent, basic_block_t **bb)
21972235
if (get_operator_prio(top_op) >= get_operator_prio(op)) {
21982236
rs2 = opstack_pop();
21992237
rs1 = opstack_pop();
2238+
2239+
/* Handle pointer arithmetic for addition and subtraction */
2240+
if ((top_op == OP_add || top_op == OP_sub) &&
2241+
(rs1->ptr_level ||
2242+
(rs1->type && rs1->type->ptr_level > 0) ||
2243+
rs2->ptr_level ||
2244+
(rs2->type && rs2->type->ptr_level > 0))) {
2245+
var_t *ptr_var = NULL;
2246+
var_t *int_var = NULL;
2247+
int element_size = 0;
2248+
2249+
/* Determine which operand is the pointer */
2250+
if (rs1->ptr_level ||
2251+
(rs1->type && rs1->type->ptr_level > 0)) {
2252+
ptr_var = rs1;
2253+
int_var = rs2;
2254+
2255+
/* Calculate element size */
2256+
if (rs1->ptr_level && rs1->type) {
2257+
element_size = rs1->type->size;
2258+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2259+
/* Typedef pointer */
2260+
switch (rs1->type->base_type) {
2261+
case TYPE_char:
2262+
element_size = TY_char->size;
2263+
break;
2264+
case TYPE_int:
2265+
element_size = TY_int->size;
2266+
break;
2267+
case TYPE_void:
2268+
element_size = 1;
2269+
break;
2270+
default:
2271+
element_size =
2272+
rs1->type ? rs1->type->size : PTR_SIZE;
2273+
break;
2274+
}
2275+
}
2276+
} else if (rs2->ptr_level ||
2277+
(rs2->type && rs2->type->ptr_level > 0)) {
2278+
/* Only for addition (p + n == n + p) */
2279+
if (top_op == OP_add) {
2280+
ptr_var = rs2;
2281+
int_var = rs1;
2282+
2283+
/* Calculate element size */
2284+
if (rs2->ptr_level && rs2->type) {
2285+
element_size = rs2->type->size;
2286+
} else if (rs2->type &&
2287+
rs2->type->ptr_level > 0) {
2288+
/* Typedef pointer */
2289+
switch (rs2->type->base_type) {
2290+
case TYPE_char:
2291+
element_size = TY_char->size;
2292+
break;
2293+
case TYPE_int:
2294+
element_size = TY_int->size;
2295+
break;
2296+
case TYPE_void:
2297+
element_size = 1;
2298+
break;
2299+
default:
2300+
element_size = rs2->type
2301+
? rs2->type->size
2302+
: PTR_SIZE;
2303+
break;
2304+
}
2305+
}
2306+
/* Swap operands so pointer is rs1 */
2307+
rs1 = ptr_var;
2308+
rs2 = int_var;
2309+
}
2310+
}
2311+
2312+
/* If we need to scale the integer operand */
2313+
if (ptr_var && element_size > 1) {
2314+
/* Create multiplication by element size */
2315+
var_t *size_const = require_var(parent);
2316+
gen_name_to(size_const->var_name);
2317+
size_const->init_val = element_size;
2318+
add_insn(parent, *bb, OP_load_constant, size_const,
2319+
NULL, NULL, 0, NULL);
2320+
2321+
var_t *scaled = require_var(parent);
2322+
gen_name_to(scaled->var_name);
2323+
add_insn(parent, *bb, OP_mul, scaled, int_var,
2324+
size_const, 0, NULL);
2325+
2326+
/* Use scaled value as rs2 */
2327+
rs2 = scaled;
2328+
}
2329+
}
2330+
22002331
vd = require_var(parent);
22012332
gen_name_to(vd->var_name);
22022333
opstack_push(vd);
@@ -2312,6 +2443,92 @@ void read_expr(block_t *parent, basic_block_t **bb)
23122443
rs2 = opstack_pop();
23132444
rs1 = opstack_pop();
23142445

2446+
/* Handle pointer arithmetic for addition and subtraction */
2447+
if ((top_op == OP_add || top_op == OP_sub) &&
2448+
(rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0) ||
2449+
rs2->ptr_level || (rs2->type && rs2->type->ptr_level > 0))) {
2450+
var_t *ptr_var = NULL;
2451+
var_t *int_var = NULL;
2452+
int element_size = 0;
2453+
2454+
/* Determine which operand is the pointer */
2455+
if (rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0)) {
2456+
ptr_var = rs1;
2457+
int_var = rs2;
2458+
2459+
/* Calculate element size */
2460+
if (rs1->ptr_level && rs1->type) {
2461+
element_size = rs1->type->size;
2462+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2463+
/* Typedef pointer */
2464+
switch (rs1->type->base_type) {
2465+
case TYPE_char:
2466+
element_size = TY_char->size;
2467+
break;
2468+
case TYPE_int:
2469+
element_size = TY_int->size;
2470+
break;
2471+
case TYPE_void:
2472+
element_size = 1;
2473+
break;
2474+
default:
2475+
element_size = rs1->type ? rs1->type->size : PTR_SIZE;
2476+
break;
2477+
}
2478+
}
2479+
} else if (rs2->ptr_level ||
2480+
(rs2->type && rs2->type->ptr_level > 0)) {
2481+
/* Only for addition (p + n == n + p) */
2482+
if (top_op == OP_add) {
2483+
ptr_var = rs2;
2484+
int_var = rs1;
2485+
2486+
/* Calculate element size */
2487+
if (rs2->ptr_level && rs2->type) {
2488+
element_size = rs2->type->size;
2489+
} else if (rs2->type && rs2->type->ptr_level > 0) {
2490+
/* Typedef pointer */
2491+
switch (rs2->type->base_type) {
2492+
case TYPE_char:
2493+
element_size = TY_char->size;
2494+
break;
2495+
case TYPE_int:
2496+
element_size = TY_int->size;
2497+
break;
2498+
case TYPE_void:
2499+
element_size = 1;
2500+
break;
2501+
default:
2502+
element_size =
2503+
rs2->type ? rs2->type->size : PTR_SIZE;
2504+
break;
2505+
}
2506+
}
2507+
/* Swap operands so pointer is rs1 */
2508+
rs1 = ptr_var;
2509+
rs2 = int_var;
2510+
}
2511+
}
2512+
2513+
/* If we need to scale the integer operand */
2514+
if (ptr_var && element_size > 1) {
2515+
/* Create multiplication by element size */
2516+
var_t *size_const = require_var(parent);
2517+
gen_name_to(size_const->var_name);
2518+
size_const->init_val = element_size;
2519+
add_insn(parent, *bb, OP_load_constant, size_const, NULL, NULL,
2520+
0, NULL);
2521+
2522+
var_t *scaled = require_var(parent);
2523+
gen_name_to(scaled->var_name);
2524+
add_insn(parent, *bb, OP_mul, scaled, int_var, size_const, 0,
2525+
NULL);
2526+
2527+
/* Use scaled value as rs2 */
2528+
rs2 = scaled;
2529+
}
2530+
}
2531+
23152532
/* Constant folding for binary operations */
23162533
if (rs1 && rs2 && rs1->init_val && !rs1->ptr_level && !rs1->is_global &&
23172534
rs2->init_val && !rs2->ptr_level && !rs2->is_global) {
@@ -2462,11 +2679,16 @@ void read_lvalue(lvalue_t *lvalue,
24622679
}
24632680

24642681
/* var must be either a pointer or an array of some type */
2465-
if (var->ptr_level == 0 && var->array_size == 0)
2682+
/* For typedef pointers, check the type's ptr_level */
2683+
bool is_typedef_pointer = (var->type && var->type->ptr_level > 0);
2684+
if (var->ptr_level == 0 && var->array_size == 0 &&
2685+
!is_typedef_pointer)
24662686
error("Cannot apply square operator to non-pointer");
24672687

24682688
/* if nested pointer, still pointer */
2469-
if (var->ptr_level <= 1 && var->array_size == 0) {
2689+
/* Also handle typedef pointers which have ptr_level == 0 */
2690+
if ((var->ptr_level <= 1 || is_typedef_pointer) &&
2691+
var->array_size == 0) {
24702692
/* For typedef pointers, get the size of the base type that the
24712693
* pointer points to
24722694
*/
@@ -2695,7 +2917,31 @@ void read_lvalue(lvalue_t *lvalue,
26952917
side_effect[se_idx].opcode = OP_load_constant;
26962918
vd = require_var(parent);
26972919
gen_name_to(vd->var_name);
2698-
vd->init_val = 1;
2920+
2921+
/* Calculate increment size based on pointer type */
2922+
int increment_size = 1;
2923+
if (lvalue->ptr_level && !lvalue->is_reference) {
2924+
increment_size = lvalue->type->size;
2925+
} else if (!lvalue->is_reference && lvalue->type &&
2926+
lvalue->type->ptr_level > 0) {
2927+
/* This is a typedef pointer */
2928+
switch (lvalue->type->base_type) {
2929+
case TYPE_char:
2930+
increment_size = TY_char->size;
2931+
break;
2932+
case TYPE_int:
2933+
increment_size = TY_int->size;
2934+
break;
2935+
case TYPE_void:
2936+
increment_size = 1;
2937+
break;
2938+
default:
2939+
increment_size = lvalue->type->size;
2940+
break;
2941+
}
2942+
}
2943+
vd->init_val = increment_size;
2944+
26992945
side_effect[se_idx].rd = vd;
27002946
side_effect[se_idx].rs1 = NULL;
27012947
side_effect[se_idx].rs2 = NULL;
@@ -3010,6 +3256,27 @@ bool read_body_assignment(char *token,
30103256
*/
30113257
if (lvalue.ptr_level && !lvalue.is_reference)
30123258
increment_size = lvalue.type->size;
3259+
/* Also check for typedef pointers which have is_ptr == 0 */
3260+
else if (!lvalue.is_reference && lvalue.type &&
3261+
lvalue.type->ptr_level > 0) {
3262+
/* This is a typedef pointer, get the base type size */
3263+
switch (lvalue.type->base_type) {
3264+
case TYPE_char:
3265+
increment_size = TY_char->size;
3266+
break;
3267+
case TYPE_int:
3268+
increment_size = TY_int->size;
3269+
break;
3270+
case TYPE_void:
3271+
/* void pointers treated as byte pointers */
3272+
increment_size = 1;
3273+
break;
3274+
default:
3275+
/* For struct pointers and other types */
3276+
increment_size = lvalue.type->size;
3277+
break;
3278+
}
3279+
}
30133280

30143281
/* If operand is a reference, read the value and push to stack for
30153282
* the incoming addition/subtraction. Otherwise, use the top element

0 commit comments

Comments
 (0)