From fbef90a7039b994907db34fde50f6fa5e46ab535 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Wed, 3 Feb 2021 04:30:11 +0100 Subject: [PATCH] Fix a VLA problem see testcase, reduced example of a situation reported by Kyryl Melekhin in https://github.com/kyx0r/neatvi/ . Problem is that setting up the VLA sp-save in a scope that isn't entered at runtime leaves traces of it in outer scopes that then try to restore the stack pointer from uninitialized slots. --- tccgen.c | 27 ++++++++++++++++++--------- tests/tests2/123_vla_bug.c | 40 ++++++++++++++++++++++++++++++++++++++++ tests/tests2/123_vla_bug.expect | 5 +++++ tests/tests2/79_vla_continue.c | 9 ++++++--- 4 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 tests/tests2/123_vla_bug.c create mode 100644 tests/tests2/123_vla_bug.expect diff --git a/tccgen.c b/tccgen.c index b8ec47d3..2519e62e 100644 --- a/tccgen.c +++ b/tccgen.c @@ -120,7 +120,7 @@ short nb_temp_local_vars; static struct scope { struct scope *prev; - struct { int loc, num; } vla; + struct { int loc, locorig, num; } vla; struct { Sym *s; int n; } cl; int *bsym, *csym; Sym *lstk, *llstk; @@ -7268,8 +7268,12 @@ static void vla_restore(int loc) static void vla_leave(struct scope *o) { - if (o->vla.num < cur_scope->vla.num) - vla_restore(o->vla.loc); + struct scope *c = cur_scope, *v = NULL; + for (; c != o && c; c = c->prev) + if (c->vla.num) + v = c; + if (v) + vla_restore(v->vla.locorig); } /* ------------------------------------------------------------------------- */ @@ -7281,6 +7285,7 @@ void new_scope(struct scope *o) *o = *cur_scope; o->prev = cur_scope; cur_scope = o; + cur_scope->vla.num = 0; /* record local declaration stack position */ o->lstk = local_stack; @@ -7600,7 +7605,8 @@ again: goto block_after_label; } else if (t == TOK_GOTO) { - vla_restore(root_scope->vla.loc); + if (cur_scope->vla.num) + vla_restore(cur_scope->vla.locorig); if (tok == '*' && gnu_ext) { /* computed goto */ next(); @@ -8566,11 +8572,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (NODATA_WANTED) goto no_alloc; - /* save current stack pointer */ - if (root_scope->vla.loc == 0) { - struct scope *v = cur_scope; - gen_vla_sp_save(loc -= PTR_SIZE); - do v->vla.loc = loc; while ((v = v->prev)); + /* save before-VLA stack pointer if needed */ + if (cur_scope->vla.num == 0) { + if (cur_scope->prev && cur_scope->prev->vla.num) { + cur_scope->vla.locorig = cur_scope->prev->vla.loc; + } else { + gen_vla_sp_save(loc -= PTR_SIZE); + cur_scope->vla.locorig = loc; + } } vla_runtime_type_size(type, &a); diff --git a/tests/tests2/123_vla_bug.c b/tests/tests2/123_vla_bug.c new file mode 100644 index 00000000..6d92c27c --- /dev/null +++ b/tests/tests2/123_vla_bug.c @@ -0,0 +1,40 @@ +typedef __SIZE_TYPE__ size_t; +extern int printf(const char*, ...); +extern size_t strlen(const char*); +char str[] = "blabla"; +int g; +int main() +{ + //char helpme[strlen(str) + 1]; + int i = 0; +#if 0 + if (g) { + char buf[strlen(str) + 10]; + buf[0] = 0; + } +alabel: + printf("default: i = %d\n", i); +#else + for (i = 0; i < 5; i++) { + switch (i) { + case 10: + if (g) { + char buf[strlen(str) + 10]; + buf[0] = 0; + goto do_cmd; + } + break; + case 1: + printf("reached 3\n"); + do_cmd: + printf("after do_cmd"); + break; + default: + g++; + printf("default: i = %d\n", i); + break; + } + } +#endif + return 0; +} diff --git a/tests/tests2/123_vla_bug.expect b/tests/tests2/123_vla_bug.expect new file mode 100644 index 00000000..2468f809 --- /dev/null +++ b/tests/tests2/123_vla_bug.expect @@ -0,0 +1,5 @@ +default: i = 0 +reached 3 +after do_cmddefault: i = 2 +default: i = 3 +default: i = 4 diff --git a/tests/tests2/79_vla_continue.c b/tests/tests2/79_vla_continue.c index 91215c99..dd637901 100644 --- a/tests/tests2/79_vla_continue.c +++ b/tests/tests2/79_vla_continue.c @@ -48,11 +48,14 @@ void test3() int count = 10; void *addr[count]; while(count--) { - int a[f()]; + int b[f()]; + if (count >= 0) { + int a[f()]; - addr[count] = a; + addr[count] = a; - continue; + continue; + } } if(addr[9] == addr[0]) { -- 2.11.4.GIT