diff options
author | Christopher Li <sparse@chrisli.org> | 2015-02-05 21:45:15 -0800 |
---|---|---|
committer | Christopher Li <sparse@chrisli.org> | 2015-02-06 05:46:48 -0800 |
commit | de1fa7e60d3d179a1b67c47a0429b2d0ac4e4842 (patch) | |
tree | a85f7e3aade9c65addc480fb993d882b4e4cdfdc | |
parent | 1a900d9f37bb060329274970b25753181ce14223 (diff) | |
download | sparse-de1fa7e60d3d179a1b67c47a0429b2d0ac4e4842.tar.gz |
Make macro expanded string immutablereview-immutable-string
The string is shared between different macro expand.
It is wrong to modify the string in place if the string
is used in a macro. Avoid overwriting the string in that
case.
Reported-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Tested-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Signed-off-by: Christopher Li <sparse@chrisli.org>
-rw-r--r-- | char.c | 15 | ||||
-rw-r--r-- | pre-process.c | 22 | ||||
-rw-r--r-- | token.h | 3 |
3 files changed, 29 insertions, 11 deletions
@@ -93,6 +93,7 @@ struct token *get_string_constant(struct token *token, struct expression *expr) static char buffer[MAX_STRING]; int len = 0; int bits; + int esc_count = 0; while (!done) { switch (token_type(next)) { @@ -111,6 +112,8 @@ struct token *get_string_constant(struct token *token, struct expression *expr) const char *p = token->string->data; const char *end = p + token->string->length - 1; while (p < end) { + if (*p == '\\') + esc_count++; p = parse_escape(p, &v, end, bits, token->pos); if (len < MAX_STRING) buffer[len] = v; @@ -123,11 +126,13 @@ struct token *get_string_constant(struct token *token, struct expression *expr) len = MAX_STRING; } - if (len >= string->length) /* can't cannibalize */ - string = __alloc_string(len+1); - string->length = len+1; - memcpy(string->data, buffer, len); - string->data[len] = '\0'; + if (esc_count || len >= string->length) { + if (string->immutable || len >= string->length) /* can't cannibalize */ + string = __alloc_string(len+1); + string->length = len+1; + memcpy(string->data, buffer, len); + string->data[len] = '\0'; + } expr->string = string; expr->wide = is_wide; return token; diff --git a/pre-process.c b/pre-process.c index 1aa3d2c4..5c386a85 100644 --- a/pre-process.c +++ b/pre-process.c @@ -209,7 +209,7 @@ static void expand_list(struct token **list) static void preprocessor_line(struct stream *stream, struct token **line); -static struct token *collect_arg(struct token *prev, int vararg, struct position *pos) +static struct token *collect_arg(struct token *prev, int vararg, struct position *pos, int count) { struct stream *stream = input_streams + prev->pos.stream; struct token **p = &prev->next; @@ -231,6 +231,11 @@ static struct token *collect_arg(struct token *prev, int vararg, struct position 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; @@ -276,7 +281,7 @@ static int collect_arguments(struct token *start, struct token *arglist, struct arglist = arglist->next; /* skip counter */ if (!wanted) { - next = collect_arg(start, 0, &what->pos); + next = collect_arg(start, 0, &what->pos, 0); if (eof_token(next)) goto Eclosing; if (!eof_token(start->next) || !match_op(next, ')')) { @@ -286,7 +291,7 @@ static int collect_arguments(struct token *start, struct token *arglist, struct } else { for (count = 0; count < wanted; count++) { struct argcount *p = &arglist->next->count; - next = collect_arg(start, p->vararg, &what->pos); + next = collect_arg(start, p->vararg, &what->pos, p->normal); arglist = arglist->next->next; if (eof_token(next)) goto Eclosing; @@ -323,7 +328,7 @@ Efew: goto out; Emany: while (match_op(next, ',')) { - next = collect_arg(next, 0, &what->pos); + next = collect_arg(next, 0, &what->pos, 0); count++; } if (eof_token(next)) @@ -1259,8 +1264,15 @@ static struct token *parse_expansion(struct token *expansion, struct token *argl } else { try_arg(token, TOKEN_MACRO_ARGUMENT, arglist); } - if (token_type(token) == TOKEN_ERROR) + switch (token_type(token)) { + case 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; @@ -164,7 +164,8 @@ enum special_token { }; struct string { - unsigned int length; + unsigned int length:31; + unsigned int immutable:1; char data[]; }; |