aboutsummaryrefslogtreecommitdiff
path: root/tests/tcctest.c
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-08-15 05:09:31 +0200
committerMichael Matz <matz@suse.de>2016-12-15 17:47:10 +0100
commitbe6d8ffc107db78d0542b5ee2d3306e7e132725c (patch)
treefd76a1e61b710ed0cec5b5d800a3be4868be9b72 /tests/tcctest.c
parentd0d25ec7df636deaf650d31ae3b50e60659f54dd (diff)
downloadtinycc-be6d8ffc107db78d0542b5ee2d3306e7e132725c.tar.gz
tinycc-be6d8ffc107db78d0542b5ee2d3306e7e132725c.tar.bz2
Fix access-after-free with statement expressions
The return value of statement expressions might refer to local symbols, so those can't be popped. The old error message always was just a band-aid, and since disabling it for pointer types it wasn't effective anyway. It also never considered that also the vtop->sym member might have referred to such symbols (see the testcase with the local static, that used to segfault). For fixing this (can be seen better with valgrind and SYM_DEBUG) simply leave local symbols of stmt exprs on the stack.
Diffstat (limited to 'tests/tcctest.c')
-rw-r--r--tests/tcctest.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 2abbacd..7ef63b8 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -2446,10 +2446,17 @@ void typeof_test(void)
printf("a=%f b=%f c=%f\n", a, b, c);
}
+
+struct hlist_node;
+struct hlist_head {
+ struct hlist_node *first, *last;
+};
+
void statement_expr_test(void)
{
int a, i;
+ /* Basic stmt expr test */
a = 0;
for(i=0;i<10;i++) {
a += 1 +
@@ -2461,6 +2468,45 @@ void statement_expr_test(void)
}
printf("a=%d\n", a);
+ /* Test that symbols aren't freed prematurely.
+ With SYM_DEBUG valgrind will show a read from a freed
+ symbol, and tcc will show an (invalid) warning on the initialization
+ of 'ptr' below, if symbols are popped after the stmt expr. */
+ void *v = (void*)39;
+ typeof(({
+ (struct hlist_node *)v;
+ })) x;
+ typeof (x)
+ ptr = (struct hlist_node *)v;
+
+ /* This part used to segfault when symbols were popped prematurely.
+ The symbols for the static local would be overwritten with
+ helper symbols from the pre-processor expansions in between. */
+#define some_attr __attribute__((aligned(1)))
+#define tps(str) ({ \
+ static const char *t some_attr = str; \
+ t; \
+ })
+ printf ("stmtexpr: %s %s\n",
+ tps("somerandomlongstring"),
+ tps("anotherlongstring"));
+
+ /* Test that the three decls of 't' don't interact. */
+ int t = 40;
+ int b = ({ int t = 41; t; });
+ int c = ({ int t = 42; t; });
+
+ /* Test that aggregate return values work. */
+ struct hlist_head h
+ = ({
+ typedef struct hlist_head T;
+ long pre = 48;
+ T t = { (void*)43, (void*)44 };
+ long post = 49;
+ t;
+ });
+ printf ("stmtexpr: %d %d %d\n", t, b, c);
+ printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last);
}
void local_label_test(void)