Print this page
11972 resync smatch
@@ -47,10 +47,11 @@
#include "scope.h"
static struct ident_list *macros; // only needed for -dD
static int false_nesting = 0;
static int counter_macro = 0; // __COUNTER__ expansion
+static int include_level = 0;
#define INCLUDEPATHS 300
const char *includepath[INCLUDEPATHS+1] = {
"",
"/usr/include",
@@ -145,53 +146,100 @@
sparse_error(token->pos, "expected preprocessor identifier");
return 0;
}
-static void replace_with_defined(struct token *token)
+static void replace_with_bool(struct token *token, bool val)
{
static const char *string[] = { "0", "1" };
- int defined = token_defined(token);
token_type(token) = TOKEN_NUMBER;
- token->number = string[defined];
+ token->number = string[val];
}
-static int expand_one_symbol(struct token **list)
+static void replace_with_defined(struct token *token)
{
- struct token *token = *list;
- struct symbol *sym;
- static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
- static time_t t = 0;
+ replace_with_bool(token, token_defined(token));
+}
- if (token->pos.noexpand)
- return 1;
+static void replace_with_has_builtin(struct token *token)
+{
+ struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
+ replace_with_bool(token, sym && sym->builtin);
+}
- sym = lookup_macro(token->ident);
- if (sym) {
- store_macro_pos(token);
- sym->used_in = file_scope;
- return expand(list, sym);
- }
- if (token->ident == &__LINE___ident) {
+static void replace_with_has_attribute(struct token *token)
+{
+ struct symbol *sym = lookup_symbol(token->ident, NS_KEYWORD);
+ replace_with_bool(token, sym && sym->op && sym->op->attribute);
+}
+
+static void expand_line(struct token *token)
+{
replace_with_integer(token, token->pos.line);
- } else if (token->ident == &__FILE___ident) {
+}
+
+static void expand_file(struct token *token)
+{
replace_with_string(token, stream_name(token->pos.stream));
- } else if (token->ident == &__DATE___ident) {
+}
+
+static void expand_basefile(struct token *token)
+{
+ replace_with_string(token, base_filename);
+}
+
+static time_t t = 0;
+static void expand_date(struct token *token)
+{
+ static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
+
if (!t)
time(&t);
strftime(buffer, 12, "%b %e %Y", localtime(&t));
replace_with_string(token, buffer);
- } else if (token->ident == &__TIME___ident) {
+}
+
+static void expand_time(struct token *token)
+{
+ static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */
+
if (!t)
time(&t);
strftime(buffer, 9, "%T", localtime(&t));
replace_with_string(token, buffer);
- } else if (token->ident == &__COUNTER___ident) {
+}
+
+static void expand_counter(struct token *token)
+{
replace_with_integer(token, counter_macro++);
- }
+}
+
+static void expand_include_level(struct token *token)
+{
+ replace_with_integer(token, include_level - 1);
+}
+
+static int expand_one_symbol(struct token **list)
+{
+ struct token *token = *list;
+ struct symbol *sym;
+
+ if (token->pos.noexpand)
return 1;
+
+ sym = lookup_macro(token->ident);
+ if (!sym)
+ return 1;
+ store_macro_pos(token);
+ if (sym->expander) {
+ sym->expander(token);
+ return 1;
+ } else {
+ sym->used_in = file_scope;
+ return expand(list, sym);
+ }
}
static inline struct token *scan_next(struct token **where)
{
struct token *token = *where;
@@ -512,17 +560,14 @@
case TOKEN_IDENT:
left->ident = built_in_ident(buffer);
left->pos.noexpand = 0;
return 1;
- case TOKEN_NUMBER: {
- char *number = __alloc_bytes(strlen(buffer) + 1);
- memcpy(number, buffer, strlen(buffer) + 1);
+ case TOKEN_NUMBER:
token_type(left) = TOKEN_NUMBER; /* could be . + num */
- left->number = number;
+ left->number = xstrdup(buffer);
return 1;
- }
case TOKEN_SPECIAL:
if (buffer[2] && buffer[3])
break;
for (n = SPECIAL_BASE; n < SPECIAL_ARG_SEPARATOR; n++) {
@@ -849,10 +894,14 @@
stream->path = path;
}
includepath[0] = path;
}
+#ifndef PATH_MAX
+#define PATH_MAX 4096 // for Hurd where it's not defined
+#endif
+
static int try_include(const char *path, const char *filename, int flen, struct token **where, const char **next_path)
{
int fd;
int plen = strlen(path);
static char fullname[PATH_MAX];
@@ -865,12 +914,11 @@
memcpy(fullname+plen, filename, flen);
if (already_tokenized(fullname))
return 1;
fd = open(fullname, O_RDONLY);
if (fd >= 0) {
- char * streamname = __alloc_bytes(plen + flen);
- memcpy(streamname, fullname, plen + flen);
+ char *streamname = xmemdup(fullname, plen + flen);
*where = tokenize(streamname, fd, *where, next_path);
close(fd);
return 1;
}
return 0;
@@ -910,17 +958,18 @@
dp = opendir(".");
if (!dp)
return NULL;
if (!getcwd(cwd, sizeof(cwd)))
- return NULL;
+ goto close;
while ((entry = readdir(dp))) {
lstat(entry->d_name, &statbuf);
if (strcmp(entry->d_name, look_for) == 0) {
snprintf(buf, sizeof(buf), "%s/%s", cwd, entry->d_name);
+ closedir(dp);
return buf;
}
if (S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
@@ -930,14 +979,17 @@
continue;
chdir(entry->d_name);
ret = find_include("", look_for);
chdir("..");
- if (ret)
+ if (ret) {
+ closedir(dp);
return ret;
}
}
+ }
+close:
closedir(dp);
return NULL;
}
@@ -980,12 +1032,17 @@
{
char cwd[PATH_MAX];
char dir_part[PATH_MAX];
const char *file_part;
const char *include_name;
+ static int cnt;
int len;
+ /* Avoid guessing includes recursively. */
+ if (cnt++ > 1000)
+ return;
+
if (!filename || filename[0] == '\0')
return;
file_part = filename;
while ((filename = strchr(filename, '/'))) {
@@ -1418,44 +1475,20 @@
Earg:
sparse_error(token->pos, "too many instances of argument in body");
return NULL;
}
-static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
+static int do_define(struct position pos, struct token *token, struct ident *name,
+ struct token *arglist, struct token *expansion, int attr)
{
- struct token *arglist, *expansion;
- struct token *left = token->next;
struct symbol *sym;
- struct ident *name;
- int ret;
+ int ret = 1;
- if (token_type(left) != TOKEN_IDENT) {
- sparse_error(token->pos, "expected identifier to 'define'");
- return 1;
- }
-
- name = left->ident;
-
- arglist = NULL;
- expansion = left->next;
- if (!expansion->pos.whitespace) {
- if (match_op(expansion, '(')) {
- arglist = expansion;
- expansion = parse_arguments(expansion);
- if (!expansion)
- return 1;
- } else if (!eof_token(expansion)) {
- warning(expansion->pos,
- "no whitespace before object-like macro body");
- }
- }
-
expansion = parse_expansion(expansion, arglist, name);
if (!expansion)
return 1;
- ret = 1;
sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
if (sym) {
int clean;
if (attr < sym->attr)
@@ -1466,38 +1499,107 @@
if (token_list_different(sym->expansion, expansion) ||
token_list_different(sym->arglist, arglist)) {
ret = 0;
if ((clean && attr == SYM_ATTR_NORMAL)
|| sym->used_in == file_scope) {
- warning(left->pos, "preprocessor token %.*s redefined",
+ warning(pos, "preprocessor token %.*s redefined",
name->len, name->name);
info(sym->pos, "this was the original definition");
}
} else if (clean)
goto out;
}
if (!sym || sym->scope != file_scope) {
- sym = alloc_symbol(left->pos, SYM_NODE);
+ sym = alloc_symbol(pos, SYM_NODE);
bind_symbol(sym, name, NS_MACRO);
add_ident(¯os, name);
ret = 0;
}
if (!ret) {
sym->expansion = expansion;
sym->arglist = arglist;
- __free_token(token); /* Free the "define" token, but not the rest of the line */
+ if (token) /* Free the "define" token, but not the rest of the line */
+ __free_token(token);
}
sym->namespace = NS_MACRO;
sym->used_in = NULL;
sym->attr = attr;
out:
return ret;
}
+///
+// predefine a macro with a printf-formatted value
+// @name: the name of the macro
+// @weak: 0/1 for a normal or a weak define
+// @fmt: the printf format followed by it's arguments.
+//
+// The type of the value is automatically infered:
+// TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise.
+// If @fmt is null or empty, the macro is defined with an empty definition.
+void predefine(const char *name, int weak, const char *fmt, ...)
+{
+ struct ident *ident = built_in_ident(name);
+ struct token *value = &eof_token_entry;
+ int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL;
+
+ if (fmt && fmt[0]) {
+ static char buf[256];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ value = __alloc_token(0);
+ if (isdigit(buf[0])) {
+ token_type(value) = TOKEN_NUMBER;
+ value->number = xstrdup(buf);
+ } else {
+ token_type(value) = TOKEN_IDENT;
+ value->ident = built_in_ident(buf);
+ }
+ value->pos.whitespace = 1;
+ value->next = &eof_token_entry;
+ }
+
+ do_define(value->pos, NULL, ident, NULL, value, attr);
+}
+
+static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
+{
+ struct token *arglist, *expansion;
+ struct token *left = token->next;
+ struct ident *name;
+
+ if (token_type(left) != TOKEN_IDENT) {
+ sparse_error(token->pos, "expected identifier to 'define'");
+ return 1;
+ }
+
+ name = left->ident;
+
+ arglist = NULL;
+ expansion = left->next;
+ if (!expansion->pos.whitespace) {
+ if (match_op(expansion, '(')) {
+ arglist = expansion;
+ expansion = parse_arguments(expansion);
+ if (!expansion)
+ return 1;
+ } else if (!eof_token(expansion)) {
+ warning(expansion->pos,
+ "no whitespace before object-like macro body");
+ }
+ }
+
+ return do_define(left->pos, token, name, arglist, expansion, attr);
+}
+
static int handle_define(struct stream *stream, struct token **line, struct token *token)
{
return do_handle_define(stream, line, token, SYM_ATTR_NORMAL);
}
@@ -1550,17 +1652,17 @@
static int handle_strong_undef(struct stream *stream, struct token **line, struct token *token)
{
return do_handle_undef(stream, line, token, SYM_ATTR_STRONG);
}
-static int preprocessor_if(struct stream *stream, struct token *token, int true)
+static int preprocessor_if(struct stream *stream, struct token *token, int cond)
{
token_type(token) = false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF;
free_preprocessor_line(token->next);
token->next = stream->top_if;
stream->top_if = token;
- if (false_nesting || true != 1)
+ if (false_nesting || cond != 1)
false_nesting++;
return 0;
}
static int handle_ifdef(struct stream *stream, struct token **line, struct token *token)
@@ -1624,10 +1726,18 @@
break;
if (p->ident == &defined_ident) {
state = 1;
beginning = list;
break;
+ } else if (p->ident == &__has_builtin_ident) {
+ state = 4;
+ beginning = list;
+ break;
+ } else if (p->ident == &__has_attribute_ident) {
+ state = 6;
+ beginning = list;
+ break;
}
if (!expand_one_symbol(list))
continue;
if (token_type(p) != TOKEN_IDENT)
break;
@@ -1654,11 +1764,43 @@
state = 0;
if (!match_op(p, ')'))
sparse_error(p->pos, "missing ')' after \"defined\"");
*list = p->next;
continue;
+
+ // __has_builtin(x) or __has_attribute(x)
+ case 4: case 6:
+ if (match_op(p, '(')) {
+ state++;
+ } else {
+ sparse_error(p->pos, "missing '(' after \"__has_%s\"",
+ state == 4 ? "builtin" : "attribute");
+ state = 0;
}
+ *beginning = p;
+ break;
+ case 5: case 7:
+ if (token_type(p) != TOKEN_IDENT) {
+ sparse_error(p->pos, "identifier expected");
+ state = 0;
+ break;
+ }
+ if (!match_op(p->next, ')'))
+ sparse_error(p->pos, "missing ')' after \"__has_%s\"",
+ state == 5 ? "builtin" : "attribute");
+ if (state == 5)
+ replace_with_has_builtin(p);
+ else
+ replace_with_has_attribute(p);
+ state = 8;
+ *beginning = p;
+ break;
+ case 8:
+ state = 0;
+ *list = p->next;
+ continue;
+ }
list = &p->next;
}
p = constant_expression(*where, &expr);
if (!eof_token(p))
@@ -1967,13 +2109,10 @@
static int handle_line(struct stream *stream, struct token **line, struct token *token)
{
return 1;
}
-/*
- * Ignore "#ident".
- */
static int handle_ident(struct stream *stream, struct token **line, struct token *token)
{
return 1;
}
@@ -2019,10 +2158,22 @@
{ "else", handle_else },
{ "endif", handle_endif },
{ "if", handle_if },
{ "elif", handle_elif },
};
+ static struct {
+ const char *name;
+ void (*expander)(struct token *);
+ } dynamic[] = {
+ { "__LINE__", expand_line },
+ { "__FILE__", expand_file },
+ { "__BASE_FILE__", expand_basefile },
+ { "__DATE__", expand_date },
+ { "__TIME__", expand_time },
+ { "__COUNTER__", expand_counter },
+ { "__INCLUDE_LEVEL__", expand_include_level },
+ };
for (i = 0; i < ARRAY_SIZE(normal); i++) {
struct symbol *sym;
sym = create_symbol(stream, normal[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
sym->handler = normal[i].handler;
@@ -2032,10 +2183,15 @@
struct symbol *sym;
sym = create_symbol(stream, special[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
sym->handler = special[i].handler;
sym->normal = 0;
}
+ for (i = 0; i < ARRAY_SIZE(dynamic); i++) {
+ struct symbol *sym;
+ sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO);
+ sym->expander = dynamic[i].expander;
+ }
counter_macro = 0;
}
static void handle_preprocessor_line(struct stream *stream, struct token **line, struct token *start)
@@ -2113,13 +2269,15 @@
false_nesting = 0;
}
if (!stream->dirty)
stream->constant = CONSTANT_FILE_YES;
*list = next->next;
+ include_level--;
continue;
case TOKEN_STREAMBEGIN:
*list = next->next;
+ include_level++;
continue;
default:
dirty_stream(stream);
if (false_nesting) {
@@ -2177,10 +2335,16 @@
preprocessing = 0;
return token;
}
+static int is_VA_ARGS_token(struct token *token)
+{
+ return (token_type(token) == TOKEN_IDENT) &&
+ (token->ident == &__VA_ARGS___ident);
+}
+
static void dump_macro(struct symbol *sym)
{
int nargs = sym->arglist ? sym->arglist->count.normal : 0;
struct token *args[nargs];
struct token *token;
@@ -2192,31 +2356,38 @@
int narg = 0;
putchar('(');
for (; !eof_token(token); token = token->next) {
if (token_type(token) == TOKEN_ARG_COUNT)
continue;
+ if (is_VA_ARGS_token(token))
+ printf("%s...", sep);
+ else
printf("%s%s", sep, show_token(token));
args[narg++] = token;
- sep = ", ";
+ sep = ",";
}
putchar(')');
}
- putchar(' ');
token = sym->expansion;
- while (!eof_token(token)) {
+ while (token_type(token) != TOKEN_UNTAINT) {
struct token *next = token->next;
+ if (token->pos.whitespace)
+ putchar(' ');
switch (token_type(token)) {
- case TOKEN_UNTAINT:
+ case TOKEN_CONCAT:
+ printf("##");
break;
+ case TOKEN_STR_ARGUMENT:
+ printf("#");
+ /* fall-through */
+ case TOKEN_QUOTED_ARGUMENT:
case TOKEN_MACRO_ARGUMENT:
token = args[token->argnum];
/* fall-through */
default:
printf("%s", show_token(token));
- if (next->pos.whitespace)
- putchar(' ');
}
token = next;
}
putchar('\n');
}