M include/util.h => include/util.h +12 -0
@@ 112,6 112,18 @@ error_to_undecideable_cond(struct error *);
struct ast_expr *
error_get_undecideable_cond(struct error *);
+struct error *
+error_pushframe();
+
+bool
+error_ispushframe(struct error *);
+
+struct error *
+error_popframe();
+
+bool
+error_ispopframe(struct error *);
+
char *
error_str(struct error *);
M src/ast/gram.y => src/ast/gram.y +3 -2
@@ 781,8 781,9 @@ jump_statement
/*: GOTO IDENTIFIER ';'*/
/*| CONTINUE ';'*/
/*| BREAK ';'*/
- /*| RETURN ';'*/
- : RETURN expression ';'
+ : RETURN ';'
+ { $$ = ast_stmt_create_jump(lexloc(), JUMP_RETURN, NULL); }
+ | RETURN expression ';'
{ $$ = ast_stmt_create_jump(lexloc(), JUMP_RETURN, $2); }
;
M src/ast/stmt/stmt.c => src/ast/stmt/stmt.c +20 -10
@@ 189,6 189,15 @@ ast_stmt_create_jump(struct lexememarker *loc, enum ast_jump_kind kind,
struct ast_expr *
ast_stmt_jump_rv(struct ast_stmt *stmt)
{
+ assert(stmt->kind == STMT_JUMP);
+ assert(stmt->u.jump.rv);
+ return stmt->u.jump.rv;
+}
+
+bool
+ast_stmt_jump_hasrv(struct ast_stmt *stmt)
+{
+ assert(stmt->kind == STMT_JUMP);
return stmt->u.jump.rv;
}
@@ 426,15 435,13 @@ static void
ast_stmt_jump_sprint(struct ast_stmt *stmt, struct strbuilder *b)
{
assert(stmt->kind == STMT_JUMP);
- char *rv = ast_expr_str(stmt->u.jump.rv);
-
- strbuilder_printf(
- b,
- "return %s;\n",
- rv
- );
-
- free(rv);
+ strbuilder_printf(b, "return");
+ if (stmt->u.jump.rv) {
+ char *rv = ast_expr_str(stmt->u.jump.rv);
+ strbuilder_printf(b, "%s", rv);
+ free(rv);
+ }
+ strbuilder_printf(b, ";");
}
static struct ast_expr *
@@ 651,7 658,10 @@ ast_stmt_getfuncs(struct ast_stmt *stmt)
case STMT_ITERATION_E:
return ast_stmt_iteration_getfuncs(stmt);
case STMT_JUMP:
- return ast_expr_getfuncs(stmt->u.jump.rv);
+ if (stmt->u.jump.rv) {
+ return ast_expr_getfuncs(stmt->u.jump.rv);
+ }
+ return string_arr_create();
default:
assert(false);
}
M src/ast/stmt/stmt.h => src/ast/stmt/stmt.h +3 -0
@@ 39,4 39,7 @@ sel_decide(struct ast_expr *control, struct state *state);
struct error *
ast_stmt_precondsinit(struct ast_stmt *, struct state *);
+bool
+ast_stmt_jump_hasrv(struct ast_stmt *stmt);
+
#endif
M src/ast/stmt/verify.c => src/ast/stmt/verify.c +1 -1
@@ 317,6 317,7 @@ ast_stmt_absprocess(struct ast_stmt *stmt, char *fname, struct state *state,
assert(loc);
char *m = lexememarker_str(loc);
struct error *e = error_printf("%s:%s: %w", m, fname, err);
+ free(m);
return e;
}
@@ 436,7 437,6 @@ sel_decide(struct ast_expr *control, struct state *state)
if (!values_comparable(zero, v)) {
return (struct decision) {
- .decision = false,
.err = error_undecideable_cond(value_to_expr(v))
};
}
M src/props/props.c => src/props/props.c +3 -3
@@ 78,9 78,9 @@ bool
props_get(struct props *p, struct ast_expr *e)
{
/* XXX: hack for shallow not conditions, fix in TODO */
- if (ast_expr_isnot(e)) {
- return !props_contradicts(p, e);
- }
+ /*if (ast_expr_isnot(e)) {*/
+ /*return !props_contradicts(p, e);*/
+ /*}*/
for (int i = 0; i < p->n; i++) {
/* TODO: logical comparison */
if (ast_expr_equal(e, p->prop[i])) {
M src/util/util.c => src/util/util.c +35 -1
@@ 296,6 296,8 @@ struct error {
enum error_type {
ERROR_PRINTF,
ERROR_UNDECIDEABLE_COND,
+ ERROR_PUSHFRAME,
+ ERROR_POPFRAME,
} type;
union error_contents {
char *printf;
@@ 388,6 390,34 @@ findnextfmt(char **p)
}
struct error *
+error_pushframe()
+{
+ struct error *err = calloc(1, sizeof(struct error));
+ err->type = ERROR_PUSHFRAME;
+ return err;
+}
+
+bool
+error_ispushframe(struct error *err)
+{
+ return error_to(err, ERROR_PUSHFRAME);
+}
+
+struct error *
+error_popframe()
+{
+ struct error *err = calloc(1, sizeof(struct error));
+ err->type = ERROR_POPFRAME;
+ return err;
+}
+
+bool
+error_ispopframe(struct error *err)
+{
+ return error_to(err, ERROR_POPFRAME);
+}
+
+struct error *
error_undecideable_cond(struct ast_expr *cond)
{
assert(cond);
@@ 415,13 445,17 @@ char *
error_str(struct error *err)
{
char *error_type_str[] = {
- [ERROR_UNDECIDEABLE_COND] = "undecideable condition"
+ [ERROR_UNDECIDEABLE_COND] = "undecideable condition",
+ [ERROR_PUSHFRAME] = "pushed frame",
+ [ERROR_POPFRAME] = "popped frame",
};
switch (err->type) {
case ERROR_PRINTF:
return dynamic_str(err->contents.printf);
case ERROR_UNDECIDEABLE_COND:
+ case ERROR_PUSHFRAME:
+ case ERROR_POPFRAME:
return dynamic_str(error_type_str[err->type]);
default:
assert(false);
A tests/1-branches/1100-FAIL-branch-double-free.x => tests/1-branches/1100-FAIL-branch-double-free.x +14 -0
@@ 0,0 1,14 @@
+#include <stdlib.h>
+
+void
+foo(int a, int b)
+{
+ int *p;
+ p = malloc(1);
+ if (a) {
+ free(p);
+ }
+ if (b) {
+ free(p);
+ }
+}
A tests/1-branches/1100-FAIL-branch-double-free.x.EXPECTED => tests/1-branches/1100-FAIL-branch-double-free.x.EXPECTED +2 -0
@@ 0,0 1,2 @@
+1-branches/1100-FAIL-branch-double-free.x:14:1:foo | $0 | $1:
+ stdlib.h:10:31:free: double free
A tests/1-branches/1200-nested-branch.x => tests/1-branches/1200-nested-branch.x +21 -0
@@ 0,0 1,21 @@
+#include <stdlib.h>
+
+void
+foo(int a, int b)
+{
+ int *p;
+ p = malloc(1);
+ if (a) {
+ if (!b) {
+ free(p);
+ }
+ }
+ if (b) {
+ free(p);
+ }
+ if (!a) {
+ if (!b) {
+ free(p);
+ }
+ }
+}
A tests/1-branches/1300-nested-branch-return.x => tests/1-branches/1300-nested-branch-return.x +22 -0
@@ 0,0 1,22 @@
+#include <stdlib.h>
+
+void
+foo(int a, int b)
+{
+ int *p;
+ p = malloc(1);
+ if (a) {
+ free(p);
+ if (b) {
+ return;
+ }
+ }
+ if (b) {
+ free(p);
+ }
+ if (!a) {
+ if (!b) {
+ free(p);
+ }
+ }
+}