Skip to content

Commit a939ffb

Browse files
committed
Fix incorrect deref behavior
Previously, using subscription operator (literally "[]") with arrow operator (literally "->") or dot operator (literally ".") would cause incorrect dereference result due to inappropriate delayed dereference strategy. In this patch, by adding dereference instructin when encount- ered subscription operator and under correct circumstances fixes the issue.
1 parent 7a53b43 commit a939ffb

File tree

3 files changed

+74
-18
lines changed

3 files changed

+74
-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

+30-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,21 @@ 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, deference to resolve base address
1264+
* e.g. dereference of "->" in "data->raw[0]" would be performed here
1265+
*/
1266+
if (lvalue->is_reference && lvalue->is_ptr && is_member) {
1267+
ph1_ir = add_ph1_ir(OP_read);
1268+
ph1_ir->src0 = opstack_pop();
1269+
vd = require_var(parent);
1270+
strcpy(vd->var_name, gen_name());
1271+
ph1_ir->dest = vd;
1272+
opstack_push(vd);
1273+
ph1_ir->size = 4;
1274+
add_insn(parent, *bb, OP_read, ph1_ir->dest, ph1_ir->src0, NULL,
1275+
ph1_ir->size, NULL);
1276+
}
1277+
12631278
/* var must be either a pointer or an array of some type */
12641279
if (var->is_ptr == 0 && var->array_size == 0)
12651280
error("Cannot apply square operator to non-pointer");
@@ -1303,8 +1318,8 @@ void read_lvalue(lvalue_t *lvalue,
13031318
ph1_ir->src1, 0, NULL);
13041319

13051320
lex_expect(T_close_square);
1306-
is_address_got = 1;
1307-
is_member = 1;
1321+
is_address_got = true;
1322+
is_member = true;
13081323
lvalue->is_reference = true;
13091324
} else {
13101325
char token[MAX_ID_LEN];
@@ -1313,7 +1328,7 @@ void read_lvalue(lvalue_t *lvalue,
13131328
/* resolve where the pointer points at from the calculated
13141329
* address in a structure.
13151330
*/
1316-
if (is_member == 1) {
1331+
if (is_member) {
13171332
ph1_ir = add_ph1_ir(OP_read);
13181333
ph1_ir->src0 = opstack_pop();
13191334
vd = require_var(parent);
@@ -1327,7 +1342,7 @@ void read_lvalue(lvalue_t *lvalue,
13271342
} else {
13281343
lex_expect(T_dot);
13291344

1330-
if (is_address_got == 0) {
1345+
if (!is_address_got) {
13311346
ph1_ir = add_ph1_ir(OP_address_of);
13321347
ph1_ir->src0 = opstack_pop();
13331348
vd = require_var(parent);
@@ -1337,7 +1352,7 @@ void read_lvalue(lvalue_t *lvalue,
13371352
add_insn(parent, *bb, OP_address_of, ph1_ir->dest,
13381353
ph1_ir->src0, NULL, 0, NULL);
13391354

1340-
is_address_got = 1;
1355+
is_address_got = true;
13411356
}
13421357
}
13431358

@@ -1376,8 +1391,8 @@ void read_lvalue(lvalue_t *lvalue,
13761391
add_insn(parent, *bb, OP_add, ph1_ir->dest, ph1_ir->src0,
13771392
ph1_ir->src1, 0, NULL);
13781393

1379-
is_address_got = 1;
1380-
is_member = 1;
1394+
is_address_got = true;
1395+
is_member = true;
13811396
}
13821397
}
13831398

@@ -1860,7 +1875,7 @@ bool read_body_assignment(char *token,
18601875
int size = 0;
18611876

18621877
/* has memory address that we want to set */
1863-
read_lvalue(&lvalue, var, parent, bb, 0, OP_generic);
1878+
read_lvalue(&lvalue, var, parent, bb, false, OP_generic);
18641879
size = lvalue.size;
18651880

18661881
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)