Skip to content

Commit 1708134

Browse files
committed
Fix dereference behavior on mixed operators
Previously, using subscript operator (literally "[]") with arrow operator (literally "->") or dot operator (literally ".") would cause incorrect dereference result due to inappropriate delayed dereference strategy. For example, considering "data->raw[0]", this would evaluate to "data[0]", same for "data.raw[0]". In this patch, by adding dereference instruction when encountered subscript operator after parsed either arrow or dot operator, in other word, after accessed struct's member, this corrects the final evaluated address. Close #164, close #165, close #181.
1 parent 7a53b43 commit 1708134

File tree

3 files changed

+76
-18
lines changed

3 files changed

+76
-18
lines changed

src/globals.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,7 @@ void hashmap_free(hashmap_t *map)
250250
next = cur->next;
251251
free(cur->key);
252252
free(cur->val);
253-
/* FIXME: Remove this if-clause will cause double free error */
254-
if (cur != map->buckets[0])
255-
free(cur);
253+
free(cur);
256254
cur = next;
257255
}
258256
}

src/parser.c

+32-15
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ void read_lvalue(lvalue_t *lvalue,
750750
var_t *var,
751751
block_t *parent,
752752
basic_block_t **bb,
753-
int eval,
753+
bool eval,
754754
opcode_t op);
755755

756756
/* Maintain a stack of expression values and operators, depending on next
@@ -805,7 +805,7 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
805805

806806
lex_peek(T_identifier, token);
807807
var_t *var = find_var(token, parent);
808-
read_lvalue(&lvalue, var, parent, bb, 0, OP_generic);
808+
read_lvalue(&lvalue, var, parent, bb, false, OP_generic);
809809

810810
if (!lvalue.is_reference) {
811811
ph1_ir = add_ph1_ir(OP_address_of);
@@ -825,7 +825,7 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
825825
int open_bracket = lex_accept(T_open_bracket);
826826
lex_peek(T_identifier, token);
827827
var_t *var = find_var(token, parent);
828-
read_lvalue(&lvalue, var, parent, bb, 1, OP_generic);
828+
read_lvalue(&lvalue, var, parent, bb, true, OP_generic);
829829
if (open_bracket)
830830
lex_expect(T_close_bracket);
831831

@@ -962,7 +962,7 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
962962
} else if (var) {
963963
/* evalue lvalue expression */
964964
lvalue_t lvalue;
965-
read_lvalue(&lvalue, var, parent, bb, 1, prefix_op);
965+
read_lvalue(&lvalue, var, parent, bb, true, prefix_op);
966966

967967
/* is it an indirect call with function pointer? */
968968
if (lex_peek(T_open_bracket, NULL)) {
@@ -1234,13 +1234,13 @@ void read_lvalue(lvalue_t *lvalue,
12341234
var_t *var,
12351235
block_t *parent,
12361236
basic_block_t **bb,
1237-
int eval,
1237+
bool eval,
12381238
opcode_t prefix_op)
12391239
{
12401240
ph1_ir_t *ph1_ir;
12411241
var_t *vd;
1242-
int is_address_got = 0;
1243-
int is_member = 0;
1242+
bool is_address_got = false;
1243+
bool is_member = false;
12441244

12451245
/* already peeked and have the variable */
12461246
lex_expect(T_identifier);
@@ -1260,6 +1260,23 @@ void read_lvalue(lvalue_t *lvalue,
12601260
while (lex_peek(T_open_square, NULL) || lex_peek(T_arrow, NULL) ||
12611261
lex_peek(T_dot, NULL)) {
12621262
if (lex_accept(T_open_square)) {
1263+
/* if subscripted member's is not yet resolved, dereference to
1264+
* resolve base address.
1265+
* e.g., dereference of "->" in "data->raw[0]" would be performed
1266+
* here.
1267+
*/
1268+
if (lvalue->is_reference && lvalue->is_ptr && is_member) {
1269+
ph1_ir = add_ph1_ir(OP_read);
1270+
ph1_ir->src0 = opstack_pop();
1271+
vd = require_var(parent);
1272+
strcpy(vd->var_name, gen_name());
1273+
ph1_ir->dest = vd;
1274+
opstack_push(vd);
1275+
ph1_ir->size = 4;
1276+
add_insn(parent, *bb, OP_read, ph1_ir->dest, ph1_ir->src0, NULL,
1277+
ph1_ir->size, NULL);
1278+
}
1279+
12631280
/* var must be either a pointer or an array of some type */
12641281
if (var->is_ptr == 0 && var->array_size == 0)
12651282
error("Cannot apply square operator to non-pointer");
@@ -1303,8 +1320,8 @@ void read_lvalue(lvalue_t *lvalue,
13031320
ph1_ir->src1, 0, NULL);
13041321

13051322
lex_expect(T_close_square);
1306-
is_address_got = 1;
1307-
is_member = 1;
1323+
is_address_got = true;
1324+
is_member = true;
13081325
lvalue->is_reference = true;
13091326
} else {
13101327
char token[MAX_ID_LEN];
@@ -1313,7 +1330,7 @@ void read_lvalue(lvalue_t *lvalue,
13131330
/* resolve where the pointer points at from the calculated
13141331
* address in a structure.
13151332
*/
1316-
if (is_member == 1) {
1333+
if (is_member) {
13171334
ph1_ir = add_ph1_ir(OP_read);
13181335
ph1_ir->src0 = opstack_pop();
13191336
vd = require_var(parent);
@@ -1327,7 +1344,7 @@ void read_lvalue(lvalue_t *lvalue,
13271344
} else {
13281345
lex_expect(T_dot);
13291346

1330-
if (is_address_got == 0) {
1347+
if (!is_address_got) {
13311348
ph1_ir = add_ph1_ir(OP_address_of);
13321349
ph1_ir->src0 = opstack_pop();
13331350
vd = require_var(parent);
@@ -1337,7 +1354,7 @@ void read_lvalue(lvalue_t *lvalue,
13371354
add_insn(parent, *bb, OP_address_of, ph1_ir->dest,
13381355
ph1_ir->src0, NULL, 0, NULL);
13391356

1340-
is_address_got = 1;
1357+
is_address_got = true;
13411358
}
13421359
}
13431360

@@ -1376,8 +1393,8 @@ void read_lvalue(lvalue_t *lvalue,
13761393
add_insn(parent, *bb, OP_add, ph1_ir->dest, ph1_ir->src0,
13771394
ph1_ir->src1, 0, NULL);
13781395

1379-
is_address_got = 1;
1380-
is_member = 1;
1396+
is_address_got = true;
1397+
is_member = true;
13811398
}
13821399
}
13831400

@@ -1860,7 +1877,7 @@ bool read_body_assignment(char *token,
18601877
int size = 0;
18611878

18621879
/* has memory address that we want to set */
1863-
read_lvalue(&lvalue, var, parent, bb, 0, OP_generic);
1880+
read_lvalue(&lvalue, var, parent, bb, false, OP_generic);
18641881
size = lvalue.size;
18651882

18661883
if (lex_accept(T_increment)) {

tests/driver.sh

+43
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,49 @@ int main() {
433433
}
434434
EOF
435435

436+
# Mixed subscript and arrow / dot operators,
437+
# excerpted and modified from issue #165
438+
try_output 0 "DDDDDDMMMEEE1" << EOF
439+
#include <stdlib.h>
440+
#include <string.h>
441+
442+
char a[100];
443+
444+
typedef struct {
445+
char *raw;
446+
} data_t;
447+
448+
int main() {
449+
strcpy(a, "DATA");
450+
data_t *data = malloc(sizeof(data_t));
451+
data->raw = a;
452+
data_t data2;
453+
data2.raw = a;
454+
char *raw = data->raw;
455+
char *raw2 = data2.raw;
456+
/* mixed arrow / dot with subscript operators dereference */
457+
printf("%c", a[0]);
458+
printf("%c", raw[0]);
459+
printf("%c", data->raw[0]);
460+
printf("%c", a[0]);
461+
printf("%c", raw2[0]);
462+
printf("%c", data2.raw[0]);
463+
/* mixed arrow / dot with subscript operators assignment */
464+
data2.raw[0] = 'M';
465+
data->raw[1] = 'E';
466+
printf("%c", a[0]);
467+
printf("%c", raw[0]);
468+
printf("%c", data->raw[0]);
469+
printf("%c", a[1]);
470+
printf("%c", raw2[1]);
471+
printf("%c", data2.raw[1]);
472+
/* their addresses should be same */
473+
printf("%d", &data2.raw[0] == &data->raw[0]);
474+
free(data);
475+
return 0;
476+
}
477+
EOF
478+
436479
# global initialization
437480
try_ 20 << EOF
438481
int a = 5 * 2;

0 commit comments

Comments
 (0)