aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Li <sparse@chrisli.org>2015-02-05 21:45:15 -0800
committerChristopher Li <sparse@chrisli.org>2015-02-06 05:46:48 -0800
commitde1fa7e60d3d179a1b67c47a0429b2d0ac4e4842 (patch)
treea85f7e3aade9c65addc480fb993d882b4e4cdfdc
parent1a900d9f37bb060329274970b25753181ce14223 (diff)
downloadsparse-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.c15
-rw-r--r--pre-process.c22
-rw-r--r--token.h3
3 files changed, 29 insertions, 11 deletions
diff --git a/char.c b/char.c
index 08ca2230..9bd3fc0d 100644
--- a/char.c
+++ b/char.c
@@ -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;
diff --git a/token.h b/token.h
index 8dbd80fd..af66b2b8 100644
--- a/token.h
+++ b/token.h
@@ -164,7 +164,8 @@ enum special_token {
};
struct string {
- unsigned int length;
+ unsigned int length:31;
+ unsigned int immutable:1;
char data[];
};