History

tccgen: flex arrays etc.

Fixes potential writes past the allocated space with mostly illegal flex array initializers. (60_errors_and_warnings.c :test_var_array) In exchange suspicious precautions such as section_reserve or checks with sec->data_allocated were removed. (There is an hard check 'init_assert()' for now but it's meant to be just temporary) Also, instead of filling holes, always memset(0) structures & arrays on stack. Sometimes more efficient, sometimes isn't. At least we can omit putting null initializers. About array range inititializers: Reparsing tokens has a small problem with sideeffects, for example int c = 0, dd[] = { [0 ... 1] = ++c, [2 ... 3] = ++c }; Also, instead of 'squeeze_multi_relocs()', delete pre-existing relocations in advance. This works even if secondary initializers don't even have relocations, as with [0 ... 7] = &stuff, [4] = NULL Also, in tcc.h: new macro "tcc_internal_error()"

grischka committed 6 years ago

Commit 72b520e1 parent 40395519 files · +309 −222Browse files

Unified · Split

9 files
  1. i386-asm.c +2 −2
  2. tcc.h +2 −3
  3. tccelf.c +3 −39
  4. tccgen.c +216 −160
  5. tccpp.c +8 −7
  6. tests/tests2/60_errors_and_warnings.c +9 −0
  7. tests/tests2/60_errors_and_warnings.expect +4 −1
  8. tests/tests2/90_struct-init.c +55 −8
  9. tests/tests2/90_struct-init.expect +10 −2
i386-asm.c+2−2
@@ -1517,7 +1517,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 1516 unmodified lines
15171517 } else if (r & VT_LVAL) {
15181518 reg = r & VT_VALMASK;
15191519 if (reg >= VT_CONST)
1520− tcc_error("internal compiler error");
1520+ tcc_internal_error("");
15211521 snprintf(buf, sizeof(buf), "(%%%s)",
15221522 #ifdef TCC_TARGET_X86_64
15231523 get_tok_str(TOK_ASM_rax + reg, NULL)
@@ -1530,7 +1530,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 6 unmodified lines
15301530 /* register case */
15311531 reg = r & VT_VALMASK;
15321532 if (reg >= VT_CONST)
1533− tcc_error("internal compiler error");
1533+ tcc_internal_error("");
15341534
15351535 /* choose register operand size */
15361536 if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
tcc.h+2−3
@@ -1237,6 +1237,8 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line); · 1236 unmodified lines
12371237 PUB_FUNC void _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2);
12381238 PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2);
12391239 PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2);
1240+#define tcc_internal_error(msg) tcc_error("internal compiler error\n"\
1241+ "%s:%d: in %s(): " msg, __FILE__,__LINE__,__FUNCTION__)
12401242
12411243 /* other utilities */
12421244 ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
@@ -1507,7 +1509,6 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh · 264 unmodified lines
15071509 ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
15081510 ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
15091511 ST_FUNC void *section_ptr_add(Section *sec, addr_t size);
1510−ST_FUNC void section_reserve(Section *sec, unsigned long size);
15111512 ST_FUNC Section *find_section(TCCState *s1, const char *name);
15121513 ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
15131514
@@ -1544,8 +1545,6 @@ ST_FUNC void add_array(TCCState *s1, const char *sec, int c); · 30 unmodified lines
15441545 ST_FUNC void build_got_entries(TCCState *s1);
15451546 #endif
15461547 ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
1547−ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset);
1548−
15491548 ST_FUNC addr_t get_sym_addr(TCCState *s, const char *name, int err, int forc);
15501549 ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
15511550 void (*symbol_cb)(void *ctx, const char *name, const void *val));
tccelf.c+3−39
@@ -321,14 +321,16 @@ ST_FUNC void *section_ptr_add(Section *sec, addr_t size) · 320 unmodified lines
321321 return sec->data + offset;
322322 }
323323
324+#ifndef ELF_OBJ_ONLY
324325 /* reserve at least 'size' bytes from section start */
325−ST_FUNC void section_reserve(Section *sec, unsigned long size)
326+static void section_reserve(Section *sec, unsigned long size)
326327 {
327328 if (size > sec->data_allocated)
328329 section_realloc(sec, size);
329330 if (size > sec->data_offset)
330331 sec->data_offset = size;
331332 }
333+#endif
332334
333335 static Section *find_section_create (TCCState *s1, const char *name, int create)
334336 {
@@ -762,45 +764,7 @@ ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, · 427 unmodified lines
762764 put_elf_reloca(symtab, s, offset, type, symbol, 0);
763765 }
764766
765−/* Remove relocations for section S->reloc starting at oldrelocoffset
766− that are to the same place, retaining the last of them. As side effect
767− the relocations are sorted. Possibly reduces the number of relocs. */
768−ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset)
769−{
770− Section *sr = s->reloc;
771− ElfW_Rel *r, *dest;
772− ssize_t a;
773− ElfW(Addr) addr;
774−
775− if (oldrelocoffset + sizeof(*r) >= sr->data_offset)
776− return;
777− /* The relocs we're dealing with are the result of initializer parsing.
778− So they will be mostly in order and there aren't many of them.
779− Secondly we need a stable sort (which qsort isn't). We use
780− a simple insertion sort. */
781− for (a = oldrelocoffset + sizeof(*r); a < sr->data_offset; a += sizeof(*r)) {
782− ssize_t i = a - sizeof(*r);
783− ElfW_Rel tmp = *(ElfW_Rel*)(sr->data + a);
784− addr = tmp.r_offset;
785− for (; i >= (ssize_t)oldrelocoffset &&
786− ((ElfW_Rel*)(sr->data + i))->r_offset > addr; i -= sizeof(*r)) {
787− *(ElfW_Rel*)(sr->data + i + sizeof(*r)) = *(ElfW_Rel*)(sr->data + i);
788− }
789− *(ElfW_Rel*)(sr->data + i + sizeof(*r)) = tmp;
790− }
791−
792− r = (ElfW_Rel*)(sr->data + oldrelocoffset);
793− dest = r;
794− for (; r < (ElfW_Rel*)(sr->data + sr->data_offset); r++) {
795− if (dest->r_offset != r->r_offset)
796− dest++;
797− *dest = *r;
798− }
799− sr->data_offset = (unsigned char*)dest - sr->data + sizeof(*r);
800−}
801−
802767 /* put stab debug information */
803−
804768 ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc,
805769 unsigned long value)
806770 {
tccgen.c+216−160
@@ -123,6 +123,12 @@ static struct scope { · 122 unmodified lines
123123 Sym *lstk, *llstk;
124124 } *cur_scope, *loop_scope, *root_scope;
125125
126+typedef struct {
127+ Section *sec;
128+ int local_offset;
129+ Sym *flex_array_ref;
130+} init_params;
131+
126132 /********************************************************/
127133 /* stab debug support */
128134
@@ -218,8 +224,8 @@ static int is_compatible_types(CType *type1, CType *type2); · 89 unmodified lines
218224 static int parse_btype(CType *type, AttributeDef *ad);
219225 static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);
220226 static void parse_expr_type(CType *type);
221−static void init_putv(CType *type, Section *sec, unsigned long c);
222−static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags);
227+static void init_putv(init_params *p, CType *type, unsigned long c);
228+static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags);
223229 static void block(int is_expr);
224230 static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
225231 static void decl(int l);
@@ -2167,16 +2173,17 @@ ST_FUNC int gv(int rc) · 1941 unmodified lines
21672173 } else {
21682174 if (is_float(vtop->type.t) &&
21692175 (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
2170− unsigned long offset;
21712176 /* CPUs usually cannot use float constants, so we store them
21722177 generically in data segment */
2178+ init_params p = { data_section };
2179+ unsigned long offset;
21732180 size = type_size(&vtop->type, &align);
21742181 if (NODATA_WANTED)
21752182 size = 0, align = 1;
2176− offset = section_add(data_section, size, align);
2177− vpush_ref(&vtop->type, data_section, offset, size);
2183+ offset = section_add(p.sec, size, align);
2184+ vpush_ref(&vtop->type, p.sec, offset, size);
21782185 vswap();
2179− init_putv(&vtop->type, data_section, offset);
2186+ init_putv(&p, &vtop->type, offset);
21802187 vtop->r |= VT_LVAL;
21812188 }
21822189 #ifdef CONFIG_TCC_BCHECK
@@ -5444,7 +5451,7 @@ static void parse_builtin_params(int nc, const char *args) · 3261 unmodified lines
54445451 type.t = VT_SIZE_T;
54455452 break;
54465453 default:
5447− tcc_error("internal error");
5454+ break;
54485455 }
54495456 gen_assign_cast(&type);
54505457 }
@@ -6102,7 +6109,8 @@ special_math_val: · 651 unmodified lines
61026109 problems */
61036110 vseti(VT_LOCAL, loc);
61046111 #ifdef CONFIG_TCC_BCHECK
6105− loc -= tcc_state->do_bounds_check != 0;
6112+ if (tcc_state->do_bounds_check)
6113+ --loc;
61066114 #endif
61076115 ret.c = vtop->c;
61086116 if (ret_nregs < 0)
@@ -7296,23 +7304,6 @@ static void skip_or_save_block(TokenString **str) · 1187 unmodified lines
72967304 }
72977305 }
72987306
7299−static void get_init_string(TokenString **str, int has_init)
7300−{
7301− if (has_init == 2) {
7302− *str = tok_str_alloc();
7303− /* only get strings */
7304− while (tok == TOK_STR || tok == TOK_LSTR) {
7305− tok_str_add_tok(*str);
7306− next();
7307− }
7308− tok_str_add(*str, -1);
7309− tok_str_add(*str, 0);
7310− }
7311− else
7312− skip_or_save_block(str);
7313− unget_tok(0);
7314−}
7315−
73167307 #define EXPR_CONST 1
73177308 #define EXPR_ANY 2
73187309
@@ -7343,10 +7334,22 @@ static void parse_init_elem(int expr_type) · 24 unmodified lines
73437334 }
73447335 }
73457336
7337+#if 1
7338+static void init_assert(init_params *p, int offset)
7339+{
7340+ if (p->sec ? !NODATA_WANTED && offset > p->sec->data_offset
7341+ : !nocode_wanted && offset > p->local_offset)
7342+ tcc_internal_error("initializer overflow");
7343+}
7344+#else
7345+#define init_assert(sec, offset)
7346+#endif
7347+
73467348 /* put zeros for variable based init */
7347−static void init_putz(Section *sec, unsigned long c, int size)
7349+static void init_putz(init_params *p, unsigned long c, int size)
73487350 {
7349− if (sec) {
7351+ init_assert(p, c + size);
7352+ if (p->sec) {
73507353 /* nothing to do because globals are already set to zero */
73517354 } else {
73527355 vpush_global_sym(&func_old_type, TOK_memset);
@@ -7365,6 +7368,37 @@ static void init_putz(Section *sec, unsigned long c, int size) · 12 unmodified lines
73657368 #define DIF_FIRST 1
73667369 #define DIF_SIZE_ONLY 2
73677370 #define DIF_HAVE_ELEM 4
7371+#define DIF_CLEAR 8
7372+
7373+/* delete relocations for specified range c ... c + size. Unfortunatly
7374+ in very special cases, relocations may occur unordered */
7375+static void decl_design_delrels(Section *sec, int c, int size)
7376+{
7377+ ElfW_Rel *rel, *rel2, *rel_end;
7378+ if (!sec || !sec->reloc)
7379+ return;
7380+ rel = rel2 = (ElfW_Rel*)sec->reloc->data;
7381+ rel_end = (ElfW_Rel*)(sec->reloc->data + sec->reloc->data_offset);
7382+ while (rel < rel_end) {
7383+ if (rel->r_offset >= c && rel->r_offset < c + size) {
7384+ sec->reloc->data_offset -= sizeof *rel;
7385+ } else {
7386+ if (rel2 != rel)
7387+ memcpy(rel2, rel, sizeof *rel);
7388+ ++rel2;
7389+ }
7390+ ++rel;
7391+ }
7392+}
7393+
7394+static void decl_design_flex(init_params *p, Sym *ref, int index)
7395+{
7396+ if (ref == p->flex_array_ref) {
7397+ if (index >= ref->c)
7398+ ref->c = index + 1;
7399+ } else if (ref->c < 0)
7400+ tcc_error("flexible array has zero size in this context");
7401+}
73687402
73697403 /* t is the array or struct type. c is the array or struct
73707404 address. cur_field is the pointer to the current
@@ -7372,13 +7406,12 @@ static void init_putz(Section *sec, unsigned long c, int size) · 1 unmodified line
73727406 index. 'flags' is as in decl_initializer.
73737407 'al' contains the already initialized length of the
73747408 current container (starting at c). This returns the new length of that. */
7375−static int decl_designator(CType *type, Section *sec, unsigned long c,
7376− Sym **cur_field, int flags, int al, int size)
7409+static int decl_designator(init_params *p, CType *type, unsigned long c,
7410+ Sym **cur_field, int flags, int al)
73777411 {
73787412 Sym *s, *f;
73797413 int index, index_last, align, l, nb_elems, elem_size;
73807414 unsigned long corig = c;
7381− TokenString *init_str = NULL;
73827415
73837416 elem_size = 0;
73847417 nb_elems = 1;
@@ -7406,9 +7439,9 @@ static int decl_designator(CType *type, Section *sec, unsigned long c, · 21 unmodified lines
74067439 }
74077440 skip(']');
74087441 s = type->ref;
7409− if (index < 0 || (s->c >= 0 && index_last >= s->c) ||
7410− index_last < index)
7411− tcc_error("invalid index");
7442+ decl_design_flex(p, s, index_last);
7443+ if (index < 0 || index_last >= s->c || index_last < index)
7444+ tcc_error("index exceeds array bounds or range is empty");
74127445 if (cur_field)
74137446 (*cur_field)->c = index_last;
74147447 type = pointed_type(type);
@@ -7444,72 +7477,82 @@ static int decl_designator(CType *type, Section *sec, unsigned long c, · 29 unmodified lines
74447477 no_designator:
74457478 if (type->t & VT_ARRAY) {
74467479 index = (*cur_field)->c;
7447− if (type->ref->c >= 0 && index >= type->ref->c)
7448− tcc_error("index too large");
7480+ s = type->ref;
7481+ decl_design_flex(p, s, index);
7482+ if (index >= s->c)
7483+ tcc_error("too many initializers");
74497484 type = pointed_type(type);
7450− c += index * type_size(type, &align);
7485+ elem_size = type_size(type, &align);
7486+ c += index * elem_size;
74517487 } else {
74527488 f = *cur_field;
74537489 while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD))
74547490 *cur_field = f = f->next;
74557491 if (!f)
7456− tcc_error("too many field init");
7492+ tcc_error("too many initializers");
74577493 type = &f->type;
74587494 c += f->c;
74597495 }
74607496 }
74617497
7462− /* must put zero in holes (note that doing it that way
7463− ensures that it even works with designators) */
7464− if (!(flags & DIF_SIZE_ONLY)) {
7465− int zlen = c - (corig + al);
7466− if (type->t & VT_BITFIELD) { /* must include current field too */
7467− zlen += type_size(type, &align);
7468− if (al + zlen > size)
7469− zlen = size - al;
7470− }
7471− if (zlen > 0)
7472− init_putz(sec, corig + al, zlen);
7473− }
7498+ if (!elem_size) /* for structs */
7499+ elem_size = type_size(type, &align);
74747500
7475− if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) {
7476− get_init_string(&init_str, tok == TOK_STR || tok == TOK_LSTR ? 2 : 0);
7477− begin_macro(init_str, 1);
7478− next();
7501+ /* Using designators the same element can be initialized more
7502+ than once. In that case we need to delete possibly already
7503+ existing relocations. */
7504+ if (!(flags & DIF_SIZE_ONLY) && c - corig < al) {
7505+ decl_design_delrels(p->sec, c, elem_size * nb_elems);
7506+ flags &= ~DIF_CLEAR; /* mark stack dirty too */
74797507 }
74807508
7481− decl_initializer(type, sec, c, flags & ~DIF_FIRST);
7509+ decl_initializer(p, type, c, flags & ~DIF_FIRST);
74827510
74837511 if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) {
7512+ Sym aref = {0};
7513+ CType t1;
74847514 int i;
7485−
7486− for(i = 1; i < nb_elems; i++) {
7487− macro_ptr = init_str->str;
7488− next();
7489− decl_initializer(type, sec, c + i * elem_size, flags & ~DIF_FIRST);
7490− }
7491− end_macro();
7492− next();
7515+ if (p->sec || (type->t & VT_ARRAY)) {
7516+ /* make init_putv/vstore believe it were a struct */
7517+ aref.c = elem_size;
7518+ t1.t = VT_STRUCT, t1.ref = &aref;
7519+ type = &t1;
7520+ }
7521+ if (p->sec)
7522+ vpush_ref(type, p->sec, c, elem_size);
7523+ else
7524+ vset(type, VT_LOCAL|VT_LVAL, c);
7525+ for (i = 1; i < nb_elems; i++) {
7526+ vdup();
7527+ init_putv(p, type, c + elem_size * i);
7528+ }
7529+ vpop();
74937530 }
74947531
7495− c += nb_elems * type_size(type, &align);
7532+ c += nb_elems * elem_size;
74967533 if (c - corig > al)
74977534 al = c - corig;
74987535 return al;
74997536 }
75007537
75017538 /* store a value or an expression directly in global data or in local array */
7502−static void init_putv(CType *type, Section *sec, unsigned long c)
7539+static void init_putv(init_params *p, CType *type, unsigned long c)
75037540 {
75047541 int bt;
75057542 void *ptr;
75067543 CType dtype;
7544+ int size, align;
7545+ Section *sec = p->sec;
75077546
75087547 dtype = *type;
75097548 dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
75107549
7550+ size = type_size(type, &align);
7551+ if (type->t & VT_BITFIELD)
7552+ size = (BIT_POS(type->t) + BIT_SIZE(type->t) + 7) / 8;
7553+ init_assert(p, c + size);
7554+
75117555 if (sec) {
7512− int size, align;
75137556 /* XXX: not portable */
75147557 /* XXX: generate error if incorrect relocation */
75157558 gen_assign_cast(&dtype);
@@ -7529,8 +7572,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 13 unmodified lines
75297572 return;
75307573 }
75317574
7532− size = type_size(type, &align);
7533− section_reserve(sec, c + size);
75347575 ptr = sec->data + c;
75357576
75367577 /* XXX: make code faster ? */
@@ -7567,12 +7608,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 30 unmodified lines
75677608 continue;
75687609 if (rel->r_offset < esym->st_value)
75697610 break;
7570− /* Note: if the same fields are initialized multiple
7571− times (possible with designators) then we possibly
7572− add multiple relocations for the same offset here.
7573− That would lead to wrong code, the last reloc needs
7574− to win. We clean this up later after the whole
7575− initializer is parsed. */
75767611 put_elf_reloca(symtab_section, sec,
75777612 c + rel->r_offset - esym->st_value,
75787613 ELFW(R_TYPE)(rel->r_info),
@@ -7610,10 +7645,10 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 31 unmodified lines
76107645 case VT_BOOL:
76117646 vtop->c.i = vtop->c.i != 0;
76127647 case VT_BYTE:
7613− *(char *)ptr |= vtop->c.i;
7648+ *(char *)ptr = vtop->c.i;
76147649 break;
76157650 case VT_SHORT:
7616− *(short *)ptr |= vtop->c.i;
7651+ *(short *)ptr = vtop->c.i;
76177652 break;
76187653 case VT_FLOAT:
76197654 *(float*)ptr = vtop->c.f;
@@ -7642,7 +7677,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 22 unmodified lines
76427677 break;
76437678 #if PTR_SIZE != 8
76447679 case VT_LLONG:
7645− *(long long *)ptr |= vtop->c.i;
7680+ *(long long *)ptr = vtop->c.i;
76467681 break;
76477682 #else
76487683 case VT_LLONG:
@@ -7654,11 +7689,11 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 5 unmodified lines
76547689 if (vtop->r & VT_SYM)
76557690 greloca(sec, vtop->sym, c, R_DATA_PTR, val);
76567691 else
7657− *(addr_t *)ptr |= val;
7692+ *(addr_t *)ptr = val;
76587693 #else
76597694 if (vtop->r & VT_SYM)
76607695 greloc(sec, vtop->sym, c, R_DATA_PTR);
7661− *(addr_t *)ptr |= val;
7696+ *(addr_t *)ptr = val;
76627697 #endif
76637698 break;
76647699 }
@@ -7669,11 +7704,11 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 4 unmodified lines
76697704 if (vtop->r & VT_SYM)
76707705 greloca(sec, vtop->sym, c, R_DATA_PTR, val);
76717706 else
7672− *(int *)ptr |= val;
7707+ *(int *)ptr = val;
76737708 #else
76747709 if (vtop->r & VT_SYM)
76757710 greloc(sec, vtop->sym, c, R_DATA_PTR);
7676− *(int *)ptr |= val;
7711+ *(int *)ptr = val;
76777712 #endif
76787713 break;
76797714 }
@@ -7693,8 +7728,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 13 unmodified lines
76937728 allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi
76947729 dimension implicit array init handling). 'flags & DIF_SIZE_ONLY' is true if
76957730 size only evaluation is wanted (only for arrays). */
7696−static void decl_initializer(CType *type, Section *sec, unsigned long c,
7697− int flags)
7731+static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags)
76987732 {
76997733 int len, n, no_oblock, i;
77007734 int size1, align1;
@@ -7702,13 +7736,17 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 1 unmodified line
77027736 Sym indexsym;
77037737 CType *t1;
77047738
7739+ /* generate line number info */
7740+ if (!p->sec && tcc_state->do_debug)
7741+ tcc_debug_line(tcc_state);
7742+
77057743 if (!(flags & DIF_HAVE_ELEM) && tok != '{' &&
77067744 /* In case of strings we have special handling for arrays, so
77077745 don't consume them as initializer value (which would commit them
77087746 to some anonymous symbol). */
77097747 tok != TOK_LSTR && tok != TOK_STR &&
77107748 !(flags & DIF_SIZE_ONLY)) {
7711− parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST);
7749+ parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST);
77127750 flags |= DIF_HAVE_ELEM;
77137751 }
77147752
@@ -7718,23 +7756,21 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 3 unmodified lines
77187756 The source type might have VT_CONSTANT set, which is
77197757 of course assignable to non-const elements. */
77207758 is_compatible_unqualified_types(type, &vtop->type)) {
7721− init_putv(type, sec, c);
7722− } else if (type->t & VT_ARRAY) {
7723− s = type->ref;
7724− n = s->c;
7725− t1 = pointed_type(type);
7726− size1 = type_size(t1, &align1);
7759+ goto init_putv;
77277760
7761+ } else if (type->t & VT_ARRAY) {
77287762 no_oblock = 1;
77297763 if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) ||
77307764 tok == '{') {
7731− if (tok != '{')
7732− tcc_error("character array initializer must be a literal,"
7733− " optionally enclosed in braces");
77347765 skip('{');
77357766 no_oblock = 0;
77367767 }
77377768
7769+ s = type->ref;
7770+ n = s->c;
7771+ t1 = pointed_type(type);
7772+ size1 = type_size(t1, &align1);
7773+
77387774 /* only parse strings here if correct type (otherwise: handle
77397775 them as ((w)char *) expressions */
77407776 if ((tok == TOK_LSTR &&
@@ -7744,7 +7780,6 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 3 unmodified lines
77447780 (t1->t & VT_BTYPE) == VT_INT
77457781 #endif
77467782 ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {
7747− int nb;
77487783 len = 0;
77497784 cstr_reset(&initstr);
77507785 if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t)))
@@ -7766,54 +7801,61 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 15 unmodified lines
77667801 unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR);
77677802 tokc.str.size = initstr.size;
77687803 tokc.str.data = initstr.data;
7769− indexsym.c = 0;
7770− f = &indexsym;
7771− goto do_init_list;
7804+ goto do_init_array;
77727805 }
7773− nb = len;
7774− if (n >= 0 && len > n)
7775− nb = n;
7806+
77767807 if (!(flags & DIF_SIZE_ONLY)) {
7777− if (sec && !NODATA_WANTED &&
7778− (c + nb > sec->data_allocated))
7779− nb = sec->data_allocated - c;
7808+ int nb = n;
7809+ if (len < nb)
7810+ nb = len;
77807811 if (len > nb)
77817812 tcc_warning("initializer-string for array is too long");
77827813 /* in order to go faster for common case (char
77837814 string in global variable, we handle it
77847815 specifically */
7785− if (sec && size1 == 1) {
7816+ if (p->sec && size1 == 1) {
7817+ init_assert(p, c + nb);
77867818 if (!NODATA_WANTED)
7787− memcpy(sec->data + c, initstr.data, nb);
7819+ memcpy(p->sec->data + c, initstr.data, nb);
77887820 } else {
7789− for(i=0;i<nb;i++) {
7790− if (size1 == 1)
7821+ for(i=0;i<n;i++) {
7822+ if (i >= nb) {
7823+ /* only add trailing zero if enough storage (no
7824+ warning in this case since it is standard) */
7825+ if (flags & DIF_CLEAR)
7826+ break;
7827+ if (n - i >= 4) {
7828+ init_putz(p, c + i * size1, (n - i) * size1);
7829+ break;
7830+ }
7831+ ch = 0;
7832+ } else if (size1 == 1)
77917833 ch = ((unsigned char *)initstr.data)[i];
77927834 else
77937835 ch = ((nwchar_t *)initstr.data)[i];
77947836 vpushi(ch);
7795− init_putv(t1, sec, c + i * size1);
7837+ init_putv(p, t1, c + i * size1);
77967838 }
77977839 }
7840+ } else {
7841+ decl_design_flex(p, s, len);
77987842 }
7799− /* only add trailing zero if enough storage (no
7800− warning in this case since it is standard) */
7801− if (n < 0 || len < n) {
7802− if (!(flags & DIF_SIZE_ONLY)) {
7803− vpushi(0);
7804− init_putv(t1, sec, c + (len * size1));
7805− }
7806− len++;
7807− }
7808− len *= size1;
78097843 } else {
7844+
7845+ do_init_array:
78107846 indexsym.c = 0;
78117847 f = &indexsym;
78127848
78137849 do_init_list:
7850+ /* zero memory once in advance */
7851+ if (!(flags & (DIF_CLEAR | DIF_SIZE_ONLY))) {
7852+ init_putz(p, c, n*size1);
7853+ flags |= DIF_CLEAR;
7854+ }
7855+
78147856 len = 0;
78157857 while (tok != '}' || (flags & DIF_HAVE_ELEM)) {
7816− len = decl_designator(type, sec, c, &f, flags, len, n*size1);
7858+ len = decl_designator(p, type, c, &f, flags, len);
78177859 flags &= ~DIF_HAVE_ELEM;
78187860 if (type->t & VT_ARRAY) {
78197861 ++indexsym.c;
@@ -7836,16 +7878,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 16 unmodified lines
78367878 skip(',');
78377879 }
78387880 }
7839− /* put zeros at the end */
7840− if (!(flags & DIF_SIZE_ONLY) && len < n*size1)
7841− init_putz(sec, c + len, n*size1 - len);
78427881 if (!no_oblock)
78437882 skip('}');
7844− /* patch type size if needed, which happens only for array types */
7845− if (n < 0)
7846− s->c = size1 == 1 ? len : ((len + size1 - 1)/size1);
78477883 } else if ((type->t & VT_BTYPE) == VT_STRUCT) {
7848− size1 = 1;
78497884 no_oblock = 1;
78507885 if ((flags & DIF_FIRST) || tok == '{') {
78517886 skip('{');
@@ -7854,12 +7889,13 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 2 unmodified lines
78547889 s = type->ref;
78557890 f = s->next;
78567891 n = s->c;
7892+ size1 = 1;
78577893 goto do_init_list;
78587894 } else if (tok == '{') {
78597895 if (flags & DIF_HAVE_ELEM)
78607896 skip(';');
78617897 next();
7862− decl_initializer(type, sec, c, flags & ~DIF_HAVE_ELEM);
7898+ decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM);
78637899 skip('}');
78647900 } else if ((flags & DIF_SIZE_ONLY)) {
78657901 /* If we supported only ISO C we wouldn't have to accept calling
@@ -7877,9 +7913,17 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 11 unmodified lines
78777913 string constant to memory too early. */
78787914 if (tok != TOK_STR && tok != TOK_LSTR)
78797915 expect("string constant");
7880− parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST);
7916+ parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST);
78817917 }
7882− init_putv(type, sec, c);
7918+ init_putv:
7919+ if (!p->sec && (flags & DIF_CLEAR) /* container was already zero'd */
7920+ && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST
7921+ && vtop->c.i == 0
7922+ && btype_size(type->t & VT_BTYPE) /* not for fp constants */
7923+ )
7924+ vpop();
7925+ else
7926+ init_putv(p, type, c);
78837927 }
78847928 }
78857929
@@ -7903,38 +7947,60 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 17 unmodified lines
79037947 #ifdef CONFIG_TCC_BCHECK
79047948 int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
79057949 #endif
7950+ init_params p = {0};
79067951
79077952 /* Always allocate static or global variables */
79087953 if (v && (r & VT_VALMASK) == VT_CONST)
79097954 nocode_wanted |= 0x80000000;
79107955
79117956 flexible_array = NULL;
7912− if ((type->t & VT_BTYPE) == VT_STRUCT) {
7957+ size = type_size(type, &align);
7958+
7959+ /* exactly one flexible array may be initialized, either the
7960+ toplevel array or the last member of the toplevel struct */
7961+
7962+ if (size < 0) {
7963+ /* If the base type itself was an array type of unspecified size
7964+ (like in 'typedef int arr[]; arr x = {1};') then we will
7965+ overwrite the unknown size by the real one for this decl.
7966+ We need to unshare the ref symbol holding that size. */
7967+ type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c);
7968+ p.flex_array_ref = type->ref;
7969+
7970+ } else if (has_init && (type->t & VT_BTYPE) == VT_STRUCT) {
79137971 Sym *field = type->ref->next;
79147972 if (field) {
79157973 while (field->next)
79167974 field = field->next;
7917− if (field->type.t & VT_ARRAY && field->type.ref->c < 0)
7975+ if (field->type.t & VT_ARRAY && field->type.ref->c < 0) {
79187976 flexible_array = field;
7977+ p.flex_array_ref = field->type.ref;
7978+ size = -1;
7979+ }
79197980 }
79207981 }
79217982
7922− size = type_size(type, &align);
7923− /* If unknown size, we must evaluate it before
7924− evaluating initializers because
7925− initializers can generate global data too
7926− (e.g. string pointers or ISOC99 compound
7927− literals). It also simplifies local
7928− initializers handling */
7929− if (size < 0 || (flexible_array && has_init)) {
7983+ if (size < 0) {
7984+ /* If unknown size, do a dry-run 1st pass */
79307985 if (!has_init)
79317986 tcc_error("unknown type size");
7932− get_init_string(&init_str, has_init);
7987+ if (has_init == 2) {
7988+ /* only get strings */
7989+ init_str = tok_str_alloc();
7990+ while (tok == TOK_STR || tok == TOK_LSTR) {
7991+ tok_str_add_tok(init_str);
7992+ next();
7993+ }
7994+ tok_str_add(init_str, -1);
7995+ tok_str_add(init_str, 0);
7996+ } else
7997+ skip_or_save_block(&init_str);
7998+ unget_tok(0);
79337999
79348000 /* compute size */
79358001 begin_macro(init_str, 1);
79368002 next();
7937− decl_initializer(type, NULL, 0, DIF_FIRST | DIF_SIZE_ONLY);
8003+ decl_initializer(&p, type, 0, DIF_FIRST | DIF_SIZE_ONLY);
79388004 /* prepare second initializer parsing */
79398005 macro_ptr = init_str->str;
79408006 next();
@@ -7943,13 +8009,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 2 unmodified lines
79438009 size = type_size(type, &align);
79448010 if (size < 0)
79458011 tcc_error("unknown type size");
8012+
8013+ /* If there's a flex member and it was used in the initializer
8014+ adjust size. */
8015+ if (flexible_array && flexible_array->type.ref->c > 0)
8016+ size += flexible_array->type.ref->c
8017+ * pointed_size(&flexible_array->type);
79468018 }
7947− /* If there's a flex member and it was used in the initializer
7948− adjust size. */
7949− if (flexible_array &&
7950− flexible_array->type.ref->c > 0)
7951− size += flexible_array->type.ref->c
7952− * pointed_size(&flexible_array->type);
8019+
79538020 /* take into account specified alignment if bigger */
79548021 if (ad->a.aligned) {
79558022 int speca = 1 << (ad->a.aligned - 1);
@@ -7972,6 +8039,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 16 unmodified lines
79728039 #endif
79738040 loc = (loc - size) & -align;
79748041 addr = loc;
8042+ p.local_offset = addr + size;
79758043 #ifdef CONFIG_TCC_BCHECK
79768044 if (bcheck && v) {
79778045 /* add padding between stack variables for bound checking */
@@ -8088,12 +8156,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 110 unmodified lines
80888156 cur_scope->vla.loc = addr;
80898157 cur_scope->vla.num++;
80908158 } else if (has_init) {
8091− size_t oldreloc_offset = 0;
8092− if (sec && sec->reloc)
8093− oldreloc_offset = sec->reloc->data_offset;
8094− decl_initializer(type, sec, addr, DIF_FIRST);
8095− if (sec && sec->reloc)
8096− squeeze_multi_relocs(sec, oldreloc_offset);
8159+ p.sec = sec;
8160+ decl_initializer(&p, type, addr, DIF_FIRST);
80978161 /* patch flexible array member size back to -1, */
80988162 /* for possible subsequent similar declarations */
80998163 if (flexible_array)
@@ -8288,14 +8352,6 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 188 unmodified lines
82888352 }
82898353 while (1) { /* iterate thru each declaration */
82908354 type = btype;
8291− /* If the base type itself was an array type of unspecified
8292− size (like in 'typedef int arr[]; arr x = {1};') then
8293− we will overwrite the unknown size by the real one for
8294− this decl. We need to unshare the ref symbol holding
8295− that size. */
8296− if ((type.t & VT_ARRAY) && type.ref->c < 0) {
8297− type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c);
8298− }
82998355 ad = adbase;
83008356 type_decl(&type, &ad, &v, TYPE_DIRECT);
83018357 #if 0
tccpp.c+8−7
@@ -2586,7 +2586,7 @@ static void parse_number(const char *p) · 2585 unmodified lines
25862586 tokc.i = n;
25872587 }
25882588 if (ch)
2589− tcc_error("invalid number\n");
2589+ tcc_error("invalid number");
25902590 }
25912591
25922592
@@ -3674,20 +3674,20 @@ static void tcc_predefs(CString *cstr) · 1081 unmodified lines
36743674 "#define __builtin_va_copy(dest,src) (dest)=(src)\n"
36753675 "#endif\n"
36763676 "#ifdef __leading_underscore\n"
3677− "#define RENAME(X) __asm__(\"_\"X)\n"
3677+ "#define __RENAME(X) __asm__(\"_\"X)\n"
36783678 "#else\n"
3679− "#define RENAME(X) __asm__(X)\n"
3679+ "#define __RENAME(X) __asm__(X)\n"
36803680 "#endif\n"
36813681 /* TCC BBUILTIN AND BOUNDS ALIASES */
36823682 "#ifdef __BOUNDS_CHECKING_ON\n"
3683− "#define __BUILTINBC(ret,name,params) ret __builtin_##name params RENAME(\"__bound_\"#name);\n"
3684− "#define __BOUND(ret,name,params) ret name params RENAME(\"__bound_\"#name);\n"
3683+ "#define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(\"__bound_\"#name);\n"
3684+ "#define __BOUND(ret,name,params) ret name params __RENAME(\"__bound_\"#name);\n"
36853685 "#else\n"
3686− "#define __BUILTINBC(ret,name,params) ret __builtin_##name params RENAME(#name);\n"
3686+ "#define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name);\n"
36873687 "#define __BOUND(ret,name,params)\n"
36883688 "#endif\n"
36893689 "#define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params)\n"
3690− "#define __BUILTIN(ret,name,params) ret __builtin_##name params RENAME(#name);\n"
3690+ "#define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name);\n"
36913691 "__BOTH(void*,memcpy,(void*,const void*,__SIZE_TYPE__))\n"
36923692 "__BOTH(void*,memmove,(void*,const void*,__SIZE_TYPE__))\n"
36933693 "__BOTH(void*,memset,(void*,int,__SIZE_TYPE__))\n"
@@ -3731,6 +3731,7 @@ static void tcc_predefs(CString *cstr) · 37 unmodified lines
37313731 "#undef __BOUND\n"
37323732 "#undef __BOTH\n"
37333733 "#undef __MAYBE_REDIR\n"
3734+ "#undef __RENAME\n"
37343735 , -1);
37353736 }
37363737
tests/tests2/60_errors_and_warnings.c+9−0
@@ -346,4 +346,13 @@ static struct var_len { int i; const char str[]; } var_array[] = · 345 unmodified lines
346346 { 2, "longlonglonglonglong" },
347347 { 3, "tst3" } };
348348
349+#elif defined test_var_array2
350+
351+struct c1 { int a; int b[]; };
352+struct c1 c1 = { 1, { 2, 3, 4 } };
353+
354+struct c2 { int c; struct c1 c1; };
355+struct c2 c2 = { 1, { 2, { 3, 4, 5 }}};
356+
357+/******************************************************************/
349358 #endif
tests/tests2/60_errors_and_warnings.expect+4−1
@@ -161,4 +161,7 @@ bar : 3 ; 3 · 160 unmodified lines
161161 \n
162162
163163 [test_var_array]
164−60_errors_and_warnings.c:345: warning: initializer-string for array is too long
164+60_errors_and_warnings.c:345: error: flexible array has zero size in this context
165+
166+[test_var_array2]
167+60_errors_and_warnings.c:355: error: flexible array has zero size in this context
tests/tests2/90_struct-init.c+55−8
@@ -221,19 +221,66 @@ void sys_ni(void) { printf("ni\n"); } · 220 unmodified lines
221221 void sys_one(void) { printf("one\n"); }
222222 void sys_two(void) { printf("two\n"); }
223223 void sys_three(void) { printf("three\n"); }
224+void sys_four(void) { printf("four\n"); }
224225 typedef void (*fptr)(void);
225−const fptr table[3] = {
226− [0 ... 2] = &sys_ni,
227− [0] = sys_one,
228− [1] = sys_two,
229− [2] = sys_three,
230−};
226+
227+#define array_size(a) (sizeof a / sizeof a[0])
231228
232229 void test_multi_relocs(void)
233230 {
234231 int i;
235− for (i = 0; i < sizeof(table)/sizeof(table[0]); i++)
236− table[i]();
232+
233+ static const fptr tabl1[4] = {
234+ [0 ... 3] = &sys_ni,
235+ [0] = sys_one,
236+ [1] = sys_two,
237+ [2] = sys_three,
238+ sys_four,
239+ [1 ... 2] = &sys_ni,
240+ [1] = 0,
241+ };
242+ for (i = 0; i < array_size(tabl1); i++)
243+ if (tabl1[i])
244+ tabl1[i]();
245+ else
246+ printf("(0)\n");
247+
248+ const fptr tabl2[4] = {
249+ [0 ... 3] = &sys_ni,
250+ [0] = sys_one,
251+ [1] = sys_two,
252+ [2] = sys_three,
253+ sys_four,
254+ [1 ... 2] = &sys_ni,
255+ [1] = 0,
256+ };
257+ for (i = 0; i < array_size(tabl2); i++)
258+ if (tabl2[i])
259+ tabl2[i]();
260+ else
261+ printf("(0)\n");
262+
263+ int c = 0;
264+ int dd[] = {
265+ [0 ... 1] = ++c,
266+ [2 ... 3] = ++c
267+ };
268+ for (i = 0; i < array_size(dd); i++)
269+ printf(" %d", dd[i]);
270+ printf("\n");
271+
272+ /* multi-dimensional flex array with range initializers */
273+ static char m1[][2][3] = {[0 ... 2]={{3,4,5},{6,7,8}},{{9},10},"abc"};
274+ char m2[][2][3] = {[0 ... 2]={{3,4,5},{6,7,8}},{{9},10},"abc"};
275+ int g, j, k;
276+ for (g = 2; g-- > 0;) {
277+ printf("mdfa %s: %d -", "locl\0glob" + g * 5, sizeof m1);
278+ for (i = 0; i < array_size(m1); i++)
279+ for (j = 0; j < array_size(m1[0]); j++)
280+ for (k = 0; k < array_size(m1[0][0]); k++)
281+ printf(" %d", (g ? m1:m2)[i][j][k]);
282+ printf("\n");
283+ }
237284 }
238285
239286 void test_init_ranges(void) {
tests/tests2/90_struct-init.expect+10−2
@@ -41,8 +41,16 @@ lssu2: 5 0 0 0 3 0 0 0 · 40 unmodified lines
4141 flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0
4242 ls4: 1 2 3 4
4343 one
44−two
45−three
44+(0)
45+ni
46+four
47+one
48+(0)
49+ni
50+four
51+ 1 1 2 2
52+mdfa glob: 30 - 3 4 5 6 7 8 3 4 5 6 7 8 3 4 5 6 7 8 9 0 0 10 0 0 97 98 99 0 0 0
53+mdfa locl: 30 - 3 4 5 6 7 8 3 4 5 6 7 8 3 4 5 6 7 8 9 0 0 10 0 0 97 98 99 0 0 0
4654 sea_fill0: okay
4755 sea_fill1: okay
4856 sea_fill2: okay