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
28872887 } else {
28882888 next_nomacro1();
28892889 }
2890+ //printf("token = %s\n", get_tok_str(tok, &tokc));
28902891 }
28912892
28922893 ST_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
29322933 cstr_ccat(&cstr, '\"');
29332934 st = s->d;
29342935 spc = 0;
2935− while (*st) {
2936+ while (*st >= 0) {
29362937 TOK_GET(&t, &st, &cval);
29372938 if (t != TOK_PLCHLDR
29382939 && t != TOK_NOSUBST
@@ -2972,7 +2973,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) · 33 unmodified lines
29722973 /* special case for var arg macros : ## eats the ','
29732974 if empty VA_ARGS variable. */
29742975 if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) {
2975− if (*st == 0) {
2976+ if (*st <= 0) {
29762977 /* suppress ',' '##' */
29772978 str.len -= 2;
29782979 } else {
@@ -2984,12 +2985,11 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args) · 5 unmodified lines
29842985 for(;;) {
29852986 int t1;
29862987 TOK_GET(&t1, &st, &cval);
2987− if (!t1)
2988+ if (t1 <= 0)
29882989 break;
29892990 tok_str_add2(&str, t1, &cval);
29902991 }
29912992 }
2992−
29932993 } else {
29942994 add_var:
29952995 /* 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
30313031 while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t)
30323032 tok_str_add(ws_str, t), t = *++p;
30333033 }
3034− if (t == 0 && can_read_stream) {
3034+ if (t == 0) {
30353035 end_macro();
30363036 /* also, end of scope for nested defined symbol */
30373037 sa = *nested_list;
@@ -3197,6 +3197,7 @@ static int macro_subst_tok( · 159 unmodified lines
31973197 if (parlevel)
31983198 expect(")");
31993199 str.len -= spc;
3200+ tok_str_add(&str, -1);
32003201 tok_str_add(&str, 0);
32013202 sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
32023203 sa1->d = str.str;
@@ -3366,7 +3367,7 @@ static void macro_subst( · 163 unmodified lines
33663367
33673368 while (1) {
33683369 TOK_GET(&t, &ptr, &cval);
3369− if (t == 0)
3370+ if (t <= 0)
33703371 break;
33713372
33723373 if (t >= TOK_IDENT && 0 == nosubst) {
@@ -3703,6 +3704,7 @@ static int pp_need_space(int a, int b) · 330 unmodified lines
37033704 : '+' == a ? TOK_INC == b || '+' == b
37043705 : '-' == a ? TOK_DEC == b || '-' == b
37053706 : a >= TOK_IDENT ? b >= TOK_IDENT
3707+ : a == TOK_PPNUM ? b >= TOK_IDENT
37063708 : 0;
37073709 }
37083710
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 */
85+X92 M_IF(KO)
86+X93 M_GET_METHOD(INIT, 0, INIT(KO))
87+X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))
88+X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b)
89+X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))
90+X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok)
91+X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
92+X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
93+// test begins
94+X1 TEST1(TRUE) // ==> expect ok, get ok
95+// First test with a token which is not a macro
96+X2 TEST2((INIT(ok))) // ==> expect 1, get 1
97+X3 TEST3((INIT(ok))) // ==> expect ok, get ok
98+// Then test with a token which is a macro, but should not be expanded.
99+X4 TEST2((INIT(KO))) // ==> expect 1, get 1
100+X5 TEST4(INIT(KO))
101+X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args"
tests/pp/19.expect+14−0
@@ -0,0 +1,14 @@
1+X92 M_IFI_1
2+X93 KO
3+X94 KO
4+X95 a
5+X96 M_IFI_1
6+X97 ok
7+X98 (1)(ok, nok)
8+X99 ok
9+X1 ok
10+X2 1
11+X3 ok
12+X4 1
13+X5 nok
14+X6 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__)
6+X1 net_ratelimited_function(pr_warn, "pipapo", bla);
7+X2 net_ratelimited_function(wrap(pr_warn), "bla", foo);
8+#define two m n
9+#define chain4(a,b,c,d) a ## b ## c ## d
10+X2 chain4(two,o,p,q)
11+X3 chain4(o,two,p,q)
12+X4 chain4(o,p,two,q)
13+X5 chain4(o,p,q,two)
tests/pp/20.expect+6−0
@@ -0,0 +1,6 @@
1+X1 printk(KERN_WARNING "pipapo",bla);
2+X2 printk(KERN_WARNING "bla",foo);
3+X2 twoopq
4+X3 otwopq
5+X4 optwoq
6+X5 opqtwo
tests/pp/Makefile+1−4
@@ -31,10 +31,7 @@ FILTER = 2>&1 | sed 's,$(SRC)/,,g' · 30 unmodified lines
3131
3232 # automatically generate .expect files with gcc:
3333 %.expect: # %.c
34− gcc -E -P $< >$*.expect 2>&1
35−
36−%.expect: # %.S
37− gcc -E -P $< >$*.expect 2>&1
34+ gcc -E -P $*.[cS] >$*.expect 2>&1
3835
3936 # tell make not to delete
4037 .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