Skip to content

Commit 4b1627c

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 4b1627c

File tree

3 files changed

+75
-18
lines changed

3 files changed

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

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

13051321
lex_expect(T_close_square);
1306-
is_address_got = 1;
1307-
is_member = 1;
1322+
is_address_got = true;
1323+
is_member = true;
13081324
lvalue->is_reference = true;
13091325
} else {
13101326
char token[MAX_ID_LEN];
@@ -1313,7 +1329,7 @@ void read_lvalue(lvalue_t *lvalue,
13131329
/* resolve where the pointer points at from the calculated
13141330
* address in a structure.
13151331
*/
1316-
if (is_member == 1) {
1332+
if (is_member) {
13171333
ph1_ir = add_ph1_ir(OP_read);
13181334
ph1_ir->src0 = opstack_pop();
13191335
vd = require_var(parent);
@@ -1327,7 +1343,7 @@ void read_lvalue(lvalue_t *lvalue,
13271343
} else {
13281344
lex_expect(T_dot);
13291345

1330-
if (is_address_got == 0) {
1346+
if (!is_address_got) {
13311347
ph1_ir = add_ph1_ir(OP_address_of);
13321348
ph1_ir->src0 = opstack_pop();
13331349
vd = require_var(parent);
@@ -1337,7 +1353,7 @@ void read_lvalue(lvalue_t *lvalue,
13371353
add_insn(parent, *bb, OP_address_of, ph1_ir->dest,
13381354
ph1_ir->src0, NULL, 0, NULL);
13391355

1340-
is_address_got = 1;
1356+
is_address_got = true;
13411357
}
13421358
}
13431359

@@ -1376,8 +1392,8 @@ void read_lvalue(lvalue_t *lvalue,
13761392
add_insn(parent, *bb, OP_add, ph1_ir->dest, ph1_ir->src0,
13771393
ph1_ir->src1, 0, NULL);
13781394

1379-
is_address_got = 1;
1380-
is_member = 1;
1395+
is_address_got = true;
1396+
is_member = true;
13811397
}
13821398
}
13831399

@@ -1860,7 +1876,7 @@ bool read_body_assignment(char *token,
18601876
int size = 0;
18611877

18621878
/* has memory address that we want to set */
1863-
read_lvalue(&lvalue, var, parent, bb, 0, OP_generic);
1879+
read_lvalue(&lvalue, var, parent, bb, false, OP_generic);
18641880
size = lvalue.size;
18651881

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