diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-03-12 08:07:05 +0100 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-03-16 00:48:45 +0100 |
commit | 0558317d0c7a2e20a6d82b7ef35357ec02e2ad38 (patch) | |
tree | 2eb0f950e593e0a816861a6289bc81807ec29052 | |
parent | 6e5fbe9870a8a593230a16cafc2de69aa2b91f78 (diff) | |
download | sparse-0558317d0c7a2e20a6d82b7ef35357ec02e2ad38.tar.gz |
cpp: fix redefinition of a macro during its own expansion
The presence of preprocessor directives within the arguments
of a macro invocation is Undefined Behaviour but most of
these directives, like the conditionals, are well-defined
and harmless.
OTOH, the redefinition of a macro during its own expansion makes
much less sense. However, it can be given a reasonable meaning:
* use the initial definition for the macro body
* use the new defintion for its arguments, in text order.
It's what gcc & clang do but Sparse can't handle this
because, during the expansion, a reference to the initial
macro's body is not kept. What is used instead is what is
currently associated with the macro.
Fix this by using the body associated with the macro at
the time of its invocation.
Testcase-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r-- | pre-process.c | 3 | ||||
-rw-r--r-- | validation/preprocessor/expand-redef.c | 20 |
2 files changed, 22 insertions, 1 deletions
diff --git a/pre-process.c b/pre-process.c index f2053676..c8725dc8 100644 --- a/pre-process.c +++ b/pre-process.c @@ -760,6 +760,7 @@ static int expand(struct token **list, struct symbol *sym) struct token *token = *list; struct ident *expanding = token->ident; struct token **tail; + struct token *expansion = sym->expansion; int nargs = sym->arglist ? sym->arglist->count.normal : 0; struct arg args[nargs]; @@ -779,7 +780,7 @@ static int expand(struct token **list, struct symbol *sym) expanding->tainted = 1; last = token->next; - tail = substitute(list, sym->expansion, args); + tail = substitute(list, expansion, args); /* * Note that it won't be eof - at least TOKEN_UNTAINT will be there. * We still can lose the newline flag if the sucker expands to nothing, diff --git a/validation/preprocessor/expand-redef.c b/validation/preprocessor/expand-redef.c new file mode 100644 index 00000000..0ccf0d4c --- /dev/null +++ b/validation/preprocessor/expand-redef.c @@ -0,0 +1,20 @@ +#define f(x) x x +f(1 +#undef f +#define f 2 + f) + +/* + * check-name: expand-redef + * check-command: sparse -E $file + * + * check-output-start + +1 2 1 2 + * check-output-end + * + * check-error-start +preprocessor/expand-redef.c:3:1: warning: directive in macro's argument list +preprocessor/expand-redef.c:4:1: warning: directive in macro's argument list + * check-error-end + */ |