lift handling of ->immutable into dup_token()
We need to make sure that any struct string with more than one token
refering to it will have ->immutable set; that's what de1fa7e60 ("Make
macro expanded string immutable") tried to achieve. Unfortunately, it
was not enough - constructing an example where an unexpanded argument gets
several copies is very easy (see the testcase in this commit).
A better place for dealing with that is dup_token() - that's guaranteed
to catch all such tokens and with sane code generation (== with compiler
made certain that *streampos can't be altered by stores to alloc->pos)
it's quite cheap; we already have alloc->pos in registers and checking
if the lower 6 bits happen to be 001000 or 001001 (TOKEN_STRING and
TOKEN_WIDE_STRING resp.) doesn't take much.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/pre-process.c b/pre-process.c
index be4e9d7..4e32285 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -255,7 +255,7 @@
static void preprocessor_line(struct stream *stream, struct token **line);
-static struct token *collect_arg(struct token *prev, int vararg, struct position *pos, int count)
+static struct token *collect_arg(struct token *prev, int vararg, const struct position *pos)
{
struct stream *stream = input_streams + prev->pos.stream;
struct token **p = &prev->next;
@@ -275,11 +275,6 @@
case TOKEN_STREAMBEGIN:
*p = &eof_token_entry;
return next;
- case TOKEN_STRING:
- case TOKEN_WIDE_STRING:
- if (count > 1)
- next->string->immutable = 1;
- break;
}
if (false_nesting) {
*p = next->next;
@@ -326,7 +321,7 @@
arglist = arglist->next; /* skip counter */
if (!wanted) {
- next = collect_arg(start, 0, &what->pos, 0);
+ next = collect_arg(start, 0, &what->pos);
if (eof_token(next))
goto Eclosing;
if (!eof_token(start->next) || !match_op(next, ')')) {
@@ -336,7 +331,7 @@
} else {
for (count = 0; count < wanted; count++) {
struct argcount *p = &arglist->next->count;
- next = collect_arg(start, p->vararg, &what->pos, p->normal);
+ next = collect_arg(start, p->vararg, &what->pos);
if (eof_token(next))
goto Eclosing;
if (p->vararg && wanted == 1 && eof_token(start->next))
@@ -375,7 +370,7 @@
goto out;
Emany:
while (match_op(next, ',')) {
- next = collect_arg(next, 0, &what->pos, 0);
+ next = collect_arg(next, 0, &what->pos);
count++;
}
if (eof_token(next))
@@ -598,6 +593,8 @@
alloc->pos.stream = pos.stream;
alloc->pos.line = pos.line;
alloc->pos.pos = pos.pos;
+ if (token_type(alloc) == TOKEN_STRING || token_type(alloc) == TOKEN_WIDE_STRING)
+ token->string->immutable = 1;
return alloc;
}
@@ -1315,15 +1312,8 @@
} else {
try_arg(token, TOKEN_MACRO_ARGUMENT, arglist);
}
- switch (token_type(token)) {
- case TOKEN_ERROR:
+ if (token_type(token) == TOKEN_ERROR)
goto Earg;
-
- case TOKEN_STRING:
- case TOKEN_WIDE_STRING:
- token->string->immutable = 1;
- break;
- }
}
token = alloc_token(&expansion->pos);
token_type(token) = TOKEN_UNTAINT;
diff --git a/validation/preprocessor/double-escapes.c b/validation/preprocessor/double-escapes.c
new file mode 100644
index 0000000..9142ad0
--- /dev/null
+++ b/validation/preprocessor/double-escapes.c
@@ -0,0 +1,8 @@
+#define A(x) x, x
+#define B(x,y) x ## y, x ## y
+static char *p[] = {A("\\")};
+static char *q[] = {B("\\", )};
+/*
+ * check-name: double escapes
+ * check-command: sparse $file
+ */