From 9656560f144380bcebade03a6c10b8c186ad3874 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Sat, 3 Sep 2016 23:55:54 +0200 Subject: [PATCH] Fix sizeof(char[a]) The sizes of VLAs need to be evaluated even inside sizeof, i.e. when nocode_wanted is set. --- tccgen.c | 27 +++++++++++++++------------ tests/tcctest.c | 10 ++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/tccgen.c b/tccgen.c index f79d30e..410dcb7 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3792,7 +3792,7 @@ static int asm_label_instr(void) return v; } -static void post_type(CType *type, AttributeDef *ad) +static void post_type(CType *type, AttributeDef *ad, int storage) { int n, l, t1, arg_size, align; Sym **plast, *s, *first; @@ -3870,6 +3870,7 @@ static void post_type(CType *type, AttributeDef *ad) type->t = VT_FUNC; type->ref = s; } else if (tok == '[') { + int saved_nocode_wanted = nocode_wanted; /* array definition */ next(); if (tok == TOK_RESTRICT1) @@ -3877,9 +3878,16 @@ static void post_type(CType *type, AttributeDef *ad) n = -1; t1 = 0; if (tok != ']') { - if (!local_stack || nocode_wanted) - vpushi(expr_const()); - else gexpr(); + if (!local_stack || (storage & VT_STATIC)) + vpushi(expr_const()); + else { + /* VLAs (which can only happen with local_stack && !VT_STATIC) + length must always be evaluated, even under nocode_wanted, + so that its size slot is initialized (e.g. under sizeof + or typeof). */ + nocode_wanted = 0; + gexpr(); + } if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { n = vtop->c.i; if (n < 0) @@ -3892,7 +3900,7 @@ static void post_type(CType *type, AttributeDef *ad) } skip(']'); /* parse next post type */ - post_type(type, ad); + post_type(type, ad, storage); if (type->t == VT_FUNC) tcc_error("declaration of an array of functions"); t1 |= type->t & VT_VLA; @@ -3910,6 +3918,7 @@ static void post_type(CType *type, AttributeDef *ad) } if (n != -1) vpop(); + nocode_wanted = saved_nocode_wanted; /* we push an anonymous symbol which will contain the array element type */ @@ -3984,13 +3993,7 @@ static void type_decl(CType *type, AttributeDef *ad, int *v, int td) } storage = type->t & VT_STORAGE; type->t &= ~VT_STORAGE; - if (storage & VT_STATIC) { - int saved_nocode_wanted = nocode_wanted; - nocode_wanted = 1; - post_type(type, ad); - nocode_wanted = saved_nocode_wanted; - } else - post_type(type, ad); + post_type(type, ad, storage); type->t |= storage; if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) parse_attribute(ad); diff --git a/tests/tcctest.c b/tests/tcctest.c index daf788c..4e51ea1 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -2456,6 +2456,16 @@ void sizeof_test(void) printf("__alignof__(char) = %d\n", __alignof__(char)); printf("__alignof__(unsigned char) = %d\n", __alignof__(unsigned char)); printf("__alignof__(func) = %d\n", __alignof__ sizeof_test()); + + /* sizes of VLAs need to be evaluated even inside sizeof: */ + a = 2; + printf("sizeof(char[1+2*a]) = %d\n", sizeof(char[1+2*a])); + /* And checking if sizeof compound literal works. Parenthesized: */ + printf("sizeof( (struct {int i; int j;}){4,5} ) = %d\n", + sizeof( (struct {int i; int j;}){4,5} )); + /* And as direct sizeof argument (as unary expression): */ + printf("sizeof (struct {short i; short j;}){4,5} = %d\n", + sizeof (struct {short i; short j;}){4,5} ); } void typeof_test(void)