History

Fix some string literal expressions in initializers

Things like 'char x[] = { "foo"[1], 0 }' (which should initialize a two-character array 'x' with "o\0"). See added testcase.

Michael Matz committed 6 years ago

Commit 7b6931e1 parent b2d351e3 files · +97 −37Browse files

Unified · Split

3 files
  1. tcc.h +1 −1
  2. tccgen.c +52 −36
  3. tests/tcctest.c +44 −0
tcc.h+1−1
@@ -449,8 +449,8 @@ typedef union CValue { · 448 unmodified lines
449 float f;449 float f;
450 uint64_t i;450 uint64_t i;
451 struct {451 struct {
452 int size;
453 const void *data;452 const void *data;
453 int size;
454 } str;454 } str;
455 int tab[LDOUBLE_SIZE/4];455 int tab[LDOUBLE_SIZE/4];
456} CValue;456} CValue;
tccgen.c+52−36
@@ -81,6 +81,7 @@ ST_DATA int func_vc; · 80 unmodified lines
81static int last_line_num, new_file, func_ind; /* debug info control */81static int last_line_num, new_file, func_ind; /* debug info control */
82ST_DATA const char *funcname;82ST_DATA const char *funcname;
83ST_DATA CType int_type, func_old_type, char_pointer_type;83ST_DATA CType int_type, func_old_type, char_pointer_type;
84static CString initstr;
84 85
85#if PTR_SIZE == 486#if PTR_SIZE == 4
86#define VT_SIZE_T (VT_INT | VT_UNSIGNED)87#define VT_SIZE_T (VT_INT | VT_UNSIGNED)
@@ -779,6 +780,7 @@ ST_FUNC void tccgen_init(TCCState *s1) · 692 unmodified lines
779#ifdef precedence_parser780#ifdef precedence_parser
780 init_prec();781 init_prec();
781#endif782#endif
783 cstr_new(&initstr);
782}784}
783 785
784ST_FUNC int tccgen_compile(TCCState *s1)786ST_FUNC int tccgen_compile(TCCState *s1)
@@ -810,6 +812,7 @@ ST_FUNC int tccgen_compile(TCCState *s1) · 25 unmodified lines
810 812
811ST_FUNC void tccgen_finish(TCCState *s1)813ST_FUNC void tccgen_finish(TCCState *s1)
812{814{
815 cstr_free(&initstr);
813 free_inline_functions(s1);816 free_inline_functions(s1);
814 sym_pop(&global_stack, NULL, 0);817 sym_pop(&global_stack, NULL, 0);
815 sym_pop(&local_stack, NULL, 0);818 sym_pop(&local_stack, NULL, 0);
@@ -3219,7 +3222,6 @@ redo: · 2403 unmodified lines
3219 gen_cast_s(VT_INT);3222 gen_cast_s(VT_INT);
3220#endif3223#endif
3221 type1 = vtop[-1].type;3224 type1 = vtop[-1].type;
3222 type1.t &= ~VT_ARRAY;
3223 if (vtop[-1].type.t & VT_VLA)3225 if (vtop[-1].type.t & VT_VLA)
3224 vla_runtime_pointed_size(&vtop[-1].type);3226 vla_runtime_pointed_size(&vtop[-1].type);
3225 else {3227 else {
@@ -3249,6 +3251,7 @@ redo: · 23 unmodified lines
3249 {3251 {
3250 gen_opic(op);3252 gen_opic(op);
3251 }3253 }
3254 type1.t &= ~VT_ARRAY;
3252 /* put again type if gen_opic() swaped operands */3255 /* put again type if gen_opic() swaped operands */
3253 vtop->type = type1;3256 vtop->type = type1;
3254 }3257 }
@@ -7229,12 +7232,12 @@ static void parse_init_elem(int expr_type) · 3974 unmodified lines
7229 /* NOTE: symbols are accepted, as well as lvalue for anon symbols7232 /* NOTE: symbols are accepted, as well as lvalue for anon symbols
7230 (compound literals). */7233 (compound literals). */
7231 if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST7234 if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST
7232 && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL)7235 && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL)
7233 || vtop->sym->v < SYM_FIRST_ANOM))7236 || vtop->sym->v < SYM_FIRST_ANOM))
7234#ifdef TCC_TARGET_PE7237#ifdef TCC_TARGET_PE
7235 || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport)7238 || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport)
7236#endif7239#endif
7237 )7240 )
7238 tcc_error("initializer element is not constant");7241 tcc_error("initializer element is not constant");
7239 break;7242 break;
7240 case EXPR_ANY:7243 case EXPR_ANY:
@@ -7442,7 +7445,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 201 unmodified lines
7442 anonymous one. That is, there's no difference in vtop7445 anonymous one. That is, there's no difference in vtop
7443 between '(void *){x}' and '&(void *){x}'. Ignore7446 between '(void *){x}' and '&(void *){x}'. Ignore
7444 pointer typed entities here. Hopefully no real code7447 pointer typed entities here. Hopefully no real code
7445 will every use compound literals with scalar type. */7448 will ever use compound literals with scalar type. */
7446 (vtop->type.t & VT_BTYPE) != VT_PTR) {7449 (vtop->type.t & VT_BTYPE) != VT_PTR) {
7447 /* These come from compound literals, memcpy stuff over. */7450 /* These come from compound literals, memcpy stuff over. */
7448 Section *ssec;7451 Section *ssec;
@@ -7450,7 +7453,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 1 unmodified line
7450 ElfW_Rel *rel;7453 ElfW_Rel *rel;
7451 esym = elfsym(vtop->sym);7454 esym = elfsym(vtop->sym);
7452 ssec = tcc_state->sections[esym->st_shndx];7455 ssec = tcc_state->sections[esym->st_shndx];
7453 memmove (ptr, ssec->data + esym->st_value, size);7456 memmove (ptr, ssec->data + esym->st_value + (int)vtop->c.i, size);
7454 if (ssec->reloc) {7457 if (ssec->reloc) {
7455 /* We need to copy over all memory contents, and that7458 /* We need to copy over all memory contents, and that
7456 includes relocations. Use the fact that relocs are7459 includes relocations. Use the fact that relocs are
@@ -7593,7 +7596,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 136 unmodified lines
7593static void decl_initializer(CType *type, Section *sec, unsigned long c, 7596static void decl_initializer(CType *type, Section *sec, unsigned long c,
7594 int flags)7597 int flags)
7595{7598{
7596 int len, n, no_oblock, nb, i;7599 int len, n, no_oblock, i;
7597 int size1, align1;7600 int size1, align1;
7598 Sym *s, *f;7601 Sym *s, *f;
7599 Sym indexsym;7602 Sym indexsym;
@@ -7641,41 +7644,54 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, · 41 unmodified lines
7641 (t1->t & VT_BTYPE) == VT_INT7644 (t1->t & VT_BTYPE) == VT_INT
7642#endif7645#endif
7643 ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {7646 ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {
7647 int nb;
7644 len = 0;7648 len = 0;
7649 cstr_reset(&initstr);
7650 if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t)))
7651 tcc_error("unhandled string literal merging");
7645 while (tok == TOK_STR || tok == TOK_LSTR) {7652 while (tok == TOK_STR || tok == TOK_LSTR) {
7646 int cstr_len, ch;7653 if (initstr.size)
7647 7654 initstr.size -= size1;
7648 /* compute maximum number of chars wanted */
7649 if (tok == TOK_STR)7655 if (tok == TOK_STR)
7650 cstr_len = tokc.str.size;7656 len += tokc.str.size;
7651 else7657 else
7652 cstr_len = tokc.str.size / sizeof(nwchar_t);7658 len += tokc.str.size / sizeof(nwchar_t);
7653 cstr_len--;7659 len--;
7654 nb = cstr_len;7660 cstr_cat(&initstr, tokc.str.data, tokc.str.size);
7655 if (n >= 0 && nb > (n - len))7661 next();
7656 nb = n - len;7662 }
7657 if (!(flags & DIF_SIZE_ONLY)) {7663 if (tok != ')' && tok != '}' && tok != ',' && tok != ';'
7658 if (cstr_len > nb)7664 && tok != TOK_EOF) {
7659 tcc_warning("initializer-string for array is too long");7665 /* Not a lone literal but part of a bigger expression. */
7660 /* in order to go faster for common case (char7666 unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR);
7661 string in global variable, we handle it7667 tokc.str.size = initstr.size;
7662 specifically */7668 tokc.str.data = initstr.data;
7663 if (sec && tok == TOK_STR && size1 == 1) {7669 indexsym.c = 0;
7664 if (!NODATA_WANTED)7670 f = &indexsym;
7665 memcpy(sec->data + c + len, tokc.str.data, nb);7671 goto do_init_list;
7666 } else {7672 }
7667 for(i=0;i<nb;i++) {7673 nb = len;
7668 if (tok == TOK_STR)7674 if (n >= 0 && len > n)
7669 ch = ((unsigned char *)tokc.str.data)[i];7675 nb = n;
7670 else7676 if (!(flags & DIF_SIZE_ONLY)) {
7671 ch = ((nwchar_t *)tokc.str.data)[i];7677 if (len > nb)
7672 vpushi(ch);7678 tcc_warning("initializer-string for array is too long");
7673 init_putv(t1, sec, c + (len + i) * size1);7679 /* in order to go faster for common case (char
7674 }7680 string in global variable, we handle it
7681 specifically */
7682 if (sec && size1 == 1) {
7683 if (!NODATA_WANTED)
7684 memcpy(sec->data + c, initstr.data, nb);
7685 } else {
7686 for(i=0;i<nb;i++) {
7687 if (size1 == 1)
7688 ch = ((unsigned char *)initstr.data)[i];
7689 else
7690 ch = ((nwchar_t *)initstr.data)[i];
7691 vpushi(ch);
7692 init_putv(t1, sec, c + i * size1);
7675 }7693 }
7676 }7694 }
7677 len += nb;
7678 next();
7679 }7695 }
7680 /* only add trailing zero if enough storage (no7696 /* only add trailing zero if enough storage (no
7681 warning in this case since it is standard) */7697 warning in this case since it is standard) */
tests/tcctest.c+44−0
@@ -467,6 +467,48 @@ int ret(a) · 466 unmodified lines
467 return 0;467 return 0;
468}468}
469 469
470char str_ag1[] = "b";
471char str_ag2[] = { "b" };
472/*char str_bg1[] = ("cccc"); GCC accepts this with pedantic warning, TCC not */
473char str_ag3[] = { "ab"[1], 0 };
474char str_ag4[2] = { "b" };
475char str_x[2] = { "xy" "z"[2], 0 };
476char *str_ar[] = { "one", "two" };
477struct str_SS {unsigned char a[3], b; };
478struct str_SS str_sinit15 = { "r" };
479struct str_SS str_sinit16[] = { { "q" }, 2 };
480
481static void string_test2()
482{
483 char *p = "hello";
484 char a3[2] = { "p" };
485 char a4[2] = { "ab" "c"[2], 0 };
486 char *pa1 = "def" + 1;
487 char *pa2 = { "xyz" + 1 };
488 int i = 0;
489 struct str_SS ss = { { [0 ... 1] = 'a' }, 0 };
490 puts("string_test2");
491 puts(str_ag1);
492 puts(str_ag2);
493 /*puts(str_bg1);*/
494 puts(str_ag3);
495 puts(str_ag4);
496 puts(str_x);
497 puts(str_sinit15.a);
498 puts(str_sinit16[0].a);
499 puts(a3);
500 puts(a4);
501 puts(p);
502 puts("world");
503 printf("%s\n", "bla");
504 puts(str_ar[0]);
505 puts(str_ar[1]);
506 puts(ss.a);
507 puts(i >= 0 ? "one" : "two");
508 puts(pa1);
509 puts(pa2);
510}
511
470void ps(const char *s)512void ps(const char *s)
471{513{
472 int c;514 int c;
@@ -511,8 +553,10 @@ void string_test() · 38 unmodified lines
511 num(b);553 num(b);
512 b = b * 2;554 b = b * 2;
513 }555 }
556 string_test2();
514}557}
515 558
559
516void if1t(int n, int a, int b, int c)560void if1t(int n, int a, int b, int c)
517{561{
518 if (a && b) printf("if1t: %d 1 %d %d\n", n, a, b);562 if (a && b) printf("if1t: %d 1 %d %d\n", n, a, b);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t