History

tccpp: Fix corner case

See added testcase 19.c from a bug report. The problem is reading outside the arguments buffers, even though we aren't allowed to. The single can_read_stream variable is not enough, sometimes we need to be able to pop into outer contexts but not into arbitrarily outside contexts. The trick is to terminate argument tokens with a EOF (and not just with 0 that makes us pop contexts), and deal with that in the few places we have to, This enables some cleanups of the can_read_stream variable use.

Michael Matz committed 9 years ago

Commit d8fdd381 parent 16d3dbf6 files · +143 −10Browse files

Unified · Split

6 files
  1. tccpp.c +8 −6
  2. tests/pp/19.c +101 −0
  3. tests/pp/19.expect +14 −0
  4. tests/pp/20.c +13 −0
  5. tests/pp/20.expect +6 −0
  6. tests/pp/Makefile +1 −4
tccpp.c+8−6
@@ -2887,6 +2887,7 @@ static void next_nomacro_spc(void) · 2886 unmodified lines
2887 } else {2887 } else {
2888 next_nomacro1();2888 next_nomacro1();
2889 }2889 }
2890 //printf("token = %s\n", get_tok_str(tok, &tokc));
2890}2891}
2891 2892
2892ST_FUNC void next_nomacro(void)2893ST_FUNC void next_nomacro(void)
@@ -2932,7 +2933,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) · 39 unmodified lines
2932 cstr_ccat(&cstr, '\"');2933 cstr_ccat(&cstr, '\"');
2933 st = s->d;2934 st = s->d;
2934 spc = 0;2935 spc = 0;
2935 while (*st) {2936 while (*st >= 0) {
2936 TOK_GET(&t, &st, &cval);2937 TOK_GET(&t, &st, &cval);
2937 if (t != TOK_PLCHLDR2938 if (t != TOK_PLCHLDR
2938 && t != TOK_NOSUBST2939 && t != TOK_NOSUBST
@@ -2972,7 +2973,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) · 33 unmodified lines
2972 /* special case for var arg macros : ## eats the ','2973 /* special case for var arg macros : ## eats the ','
2973 if empty VA_ARGS variable. */2974 if empty VA_ARGS variable. */
2974 if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) {2975 if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) {
2975 if (*st == 0) {2976 if (*st <= 0) {
2976 /* suppress ',' '##' */2977 /* suppress ',' '##' */
2977 str.len -= 2;2978 str.len -= 2;
2978 } else {2979 } else {
@@ -2984,12 +2985,11 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) · 5 unmodified lines
2984 for(;;) {2985 for(;;) {
2985 int t1;2986 int t1;
2986 TOK_GET(&t1, &st, &cval);2987 TOK_GET(&t1, &st, &cval);
2987 if (!t1)2988 if (t1 <= 0)
2988 break;2989 break;
2989 tok_str_add2(&str, t1, &cval);2990 tok_str_add2(&str, t1, &cval);
2990 }2991 }
2991 }2992 }
2992
2993 } else {2993 } else {
2994 add_var:2994 add_var:
2995 /* NOTE: the stream cannot be read when macro2995 /* NOTE: the stream cannot be read when macro
@@ -3031,7 +3031,7 @@ static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *w · 35 unmodified lines
3031 while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t)3031 while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t)
3032 tok_str_add(ws_str, t), t = *++p;3032 tok_str_add(ws_str, t), t = *++p;
3033 }3033 }
3034 if (t == 0 && can_read_stream) {3034 if (t == 0) {
3035 end_macro();3035 end_macro();
3036 /* also, end of scope for nested defined symbol */3036 /* also, end of scope for nested defined symbol */
3037 sa = *nested_list;3037 sa = *nested_list;
@@ -3197,6 +3197,7 @@ static int macro_subst_tok( · 159 unmodified lines
3197 if (parlevel)3197 if (parlevel)
3198 expect(")");3198 expect(")");
3199 str.len -= spc;3199 str.len -= spc;
3200 tok_str_add(&str, -1);
3200 tok_str_add(&str, 0);3201 tok_str_add(&str, 0);
3201 sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);3202 sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
3202 sa1->d = str.str;3203 sa1->d = str.str;
@@ -3366,7 +3367,7 @@ static void macro_subst( · 163 unmodified lines
3366 3367
3367 while (1) {3368 while (1) {
3368 TOK_GET(&t, &ptr, &cval);3369 TOK_GET(&t, &ptr, &cval);
3369 if (t == 0)3370 if (t <= 0)
3370 break;3371 break;
3371 3372
3372 if (t >= TOK_IDENT && 0 == nosubst) {3373 if (t >= TOK_IDENT && 0 == nosubst) {
@@ -3703,6 +3704,7 @@ static int pp_need_space(int a, int b) · 330 unmodified lines
3703 : '+' == a ? TOK_INC == b || '+' == b3704 : '+' == a ? TOK_INC == b || '+' == b
3704 : '-' == a ? TOK_DEC == b || '-' == b3705 : '-' == a ? TOK_DEC == b || '-' == b
3705 : a >= TOK_IDENT ? b >= TOK_IDENT3706 : a >= TOK_IDENT ? b >= TOK_IDENT
3707 : a == TOK_PPNUM ? b >= TOK_IDENT
3706 : 0;3708 : 0;
3707}3709}
3708 3710
tests/pp/19.c+101−0
@@ -0,0 +1,101 @@
1#define M_C2I(a, ...) a ## __VA_ARGS__
2#define M_C(a, ...) M_C2I(a, __VA_ARGS__)
3#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__
4#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__)
5
6#define M_RETI_ARG2(a, b, ...) b
7#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__)
8#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa
9#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
10
11#define M_TOBOOLI_0 1, 0,
12#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless)
13
14#define M_IFI_0(true_macro, ...) __VA_ARGS__
15#define M_IFI_1(true_macro, ...) true_macro
16#define M_IF(c) M_C(M_IFI_, M_BOOL(c))
17
18#define M_FLAT(...) __VA_ARGS__
19#define M_INVI_0 1
20#define M_INVI_1 0
21#define M_INV(x) M_C(M_INVI_, x)
22
23#define M_ANDI_00 0
24#define M_ANDI_01 0
25#define M_ANDI_10 0
26#define M_ANDI_11 1
27#define M_AND(x,y) M_C3(M_ANDI_, x, y)
28
29#define M_ORI_00 0
30#define M_ORI_01 1
31#define M_ORI_10 1
32#define M_ORI_11 1
33#define M_OR(x,y) M_C3(M_ORI_, x, y)
34
35#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless)
36
37#define M_EMPTYI_DETECT(...) 0, 1,
38#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ ())
39#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__)
40#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () )
41#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTYI_P_C3(__VA_ARGS__))))
42#define M_APPLY_FUNC2B(func, arg1, arg2) \
43 M_IF(M_EMPTY_P(arg2))(,func(arg1, arg2))
44#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,...) \
45 M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \
46 M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \
47 M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \
48 M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \
49 M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \
50 M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \
51 M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \
52 M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \
53 M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z)
54#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , )
55#define M_INIT_INIT(a) ,a,
56
57#define M_GET_METHOD(method, method_default, ...) \
58 M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,)
59
60#define M_TEST_METHOD_P(method, oplist) \
61 M_BOOL(M_GET_METHOD (method, 0, M_FLAT oplist))
62
63#define TRUE 1
64#define TEST1(n) \
65 M_IF(n)(ok,nok)
66#define TEST2(op) \
67 M_TEST_METHOD_P(INIT, op)
68#define TEST3(op) \
69 M_IF(M_TEST_METHOD_P(INIT, op))(ok, nok)
70#define TEST4(op) \
71 TEST1(TEST2(op))
72#define KO(a) ((void)1)
73
74/* This checks that the various expansions that ultimately lead to
75 something like 'KO(arg,arg)', where 'KO' comes from a macro
76 expansion reducing from a large macro chain do not are regarded
77 as funclike macro invocation of KO. E.g. X93 and X94 expand to 'KO',
78 but X95 must not consume the (a,b) arguments outside the M_IF()
79 invocation to reduce the 'KO' macro to an invocation. Instead
80 X95 should reduce via M_IF(KO)(a,b) to 'a'.
81
82 The other lines here are variations on this scheme, with X1 to
83 X6 coming from the bug report at
84 http://lists.nongnu.org/archive/html/tinycc-devel/2017-07/msg00017.html */
85X92 M_IF(KO)
86X93 M_GET_METHOD(INIT, 0, INIT(KO))
87X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))
88X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b)
89X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))
90X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok)
91X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
92X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
93// test begins
94X1 TEST1(TRUE) // ==> expect ok, get ok
95// First test with a token which is not a macro
96X2 TEST2((INIT(ok))) // ==> expect 1, get 1
97X3 TEST3((INIT(ok))) // ==> expect ok, get ok
98// Then test with a token which is a macro, but should not be expanded.
99X4 TEST2((INIT(KO))) // ==> expect 1, get 1
100X5 TEST4(INIT(KO))
101X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args"
tests/pp/19.expect+14−0
@@ -0,0 +1,14 @@
1X92 M_IFI_1
2X93 KO
3X94 KO
4X95 a
5X96 M_IFI_1
6X97 ok
7X98 (1)(ok, nok)
8X99 ok
9X1 ok
10X2 1
11X3 ok
12X4 1
13X5 nok
14X6 ok
tests/pp/20.c+13−0
@@ -0,0 +1,13 @@
1/* Various things I encountered while hacking the pre processor */
2#define wrap(x) x
3#define pr_warning(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__)
4#define pr_warn(x,y) pr_warning(x,y)
5#define net_ratelimited_function(function, ...) function(__VA_ARGS__)
6X1 net_ratelimited_function(pr_warn, "pipapo", bla);
7X2 net_ratelimited_function(wrap(pr_warn), "bla", foo);
8#define two m n
9#define chain4(a,b,c,d) a ## b ## c ## d
10X2 chain4(two,o,p,q)
11X3 chain4(o,two,p,q)
12X4 chain4(o,p,two,q)
13X5 chain4(o,p,q,two)
tests/pp/20.expect+6−0
@@ -0,0 +1,6 @@
1X1 printk(KERN_WARNING "pipapo",bla);
2X2 printk(KERN_WARNING "bla",foo);
3X2 twoopq
4X3 otwopq
5X4 optwoq
6X5 opqtwo
tests/pp/Makefile+1−4
@@ -31,10 +31,7 @@ FILTER = 2>&1 | sed 's,$(SRC)/,,g' · 30 unmodified lines
31 31
32# automatically generate .expect files with gcc:32# automatically generate .expect files with gcc:
33%.expect: # %.c33%.expect: # %.c
34 gcc -E -P $< >$*.expect 2>&134 gcc -E -P $*.[cS] >$*.expect 2>&1
35
36%.expect: # %.S
37 gcc -E -P $< >$*.expect 2>&1
38 35
39# tell make not to delete36# tell make not to delete
40.PRECIOUS: %.expect37.PRECIOUS: %.expect

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