diff options
-rw-r--r-- | Documentation/release-notes/v0.6.4.rst | 2 | ||||
-rw-r--r-- | builtin.c | 8 | ||||
-rwxr-xr-x | cgcc | 7 | ||||
-rw-r--r-- | dissect.c | 61 | ||||
-rw-r--r-- | expand.c | 10 | ||||
-rw-r--r-- | expression.c | 9 | ||||
-rw-r--r-- | expression.h | 3 | ||||
-rw-r--r-- | options.c | 18 | ||||
-rw-r--r-- | options.h | 2 | ||||
-rw-r--r-- | parse.c | 8 | ||||
-rw-r--r-- | semind.c | 1 | ||||
-rw-r--r-- | sparse.c | 2 | ||||
-rw-r--r-- | test-dissect.c | 5 | ||||
-rw-r--r-- | token.h | 2 | ||||
-rw-r--r-- | validation/builtin-objsize-self-init.c | 11 | ||||
-rw-r--r-- | validation/byte-count-max.c | 28 | ||||
-rw-r--r-- | validation/char-constant-signed.c | 9 | ||||
-rw-r--r-- | validation/char-constant-unsigned.c | 9 | ||||
-rw-r--r-- | validation/label-positioning.c | 22 |
19 files changed, 204 insertions, 13 deletions
diff --git a/Documentation/release-notes/v0.6.4.rst b/Documentation/release-notes/v0.6.4.rst index 387870fa..08830bd8 100644 --- a/Documentation/release-notes/v0.6.4.rst +++ b/Documentation/release-notes/v0.6.4.rst @@ -1,4 +1,4 @@ -v0.6.4 (2020-09-06) +v0.6.4 (2021-09-06) =================== Fixes: @@ -546,11 +546,19 @@ static int expand_object_size(struct expression *expr, int cost) // a deref is just intermediate variable // and so the offset needs to be zeroed. if (arg->op == '*') { + struct expression *parent = arg; arg = arg->unop; off = 0; switch (arg->type) { case EXPR_SYMBOL: arg = arg->symbol->initializer; + if (arg == parent) { + // stop at self-initialized vars + // and do not expand them. + arg = NULL; + val = -1; + break; + } continue; default: break; @@ -292,6 +292,9 @@ sub add_specs { } elsif ($spec eq 'aarch64') { return (' --arch=aarch64' . &float_types (1, 1, 36, [24,8], [53,11], [113,15])); + } elsif ($spec eq 'xtensa') { + return (' --arch=xtensa' . + &float_types (1, 1, 21, [24,8], [53,11], [53,11])); } elsif ($spec eq 'host_os_specs') { my $os = `uname -s`; chomp $os; @@ -319,6 +322,8 @@ sub add_specs { return &add_specs ('x86_64') . ' -mx32'; } elsif ($gccmachine =~ '^x86_64-') { return &add_specs ('x86_64'); + } elsif ($gccmachine =~ '^xtensa-') { + return &add_specs ('xtensa'); } # fall back to uname -m to determine the specifics. @@ -348,6 +353,8 @@ sub add_specs { return &add_specs ('arm'); } elsif ($arch =~ /^(aarch64)$/i) { return &add_specs ('aarch64'); + } elsif ($arch =~ /^(xtensa)$/i) { + return &add_specs ('xtensa'); } } else { die "$0: invalid specs: $spec\n"; @@ -610,6 +610,16 @@ static struct symbol *do_initializer(struct symbol *type, struct expression *exp return type; } +static inline bool is_macro(struct symbol *sym) +{ + return (sym->namespace == NS_MACRO || sym->namespace == NS_UNDEF); +} + +static inline bool is_typedef(struct symbol *sym) +{ + return (sym->namespace == NS_TYPEDEF); +} + static inline struct symbol *do_symbol(struct symbol *sym) { struct symbol *type = base_type(sym); @@ -652,9 +662,58 @@ static void do_sym_list(struct symbol_list *list) DO_LIST(list, sym, do_symbol(sym)); } +static inline bool valid_namespace(enum namespace ns) +{ + return (ns == NS_TYPEDEF || ns == NS_MACRO || ns == NS_UNDEF || ns == NS_STRUCT || ns == NS_SYMBOL); +} + +static void do_file(char *file) +{ + struct symbol_list *res = sparse_keep_tokens(file); + + if (!dissect_show_all_symbols) { + do_sym_list(res); + goto end; + } + + DO_LIST(file_scope->symbols, sym, + if (input_streams[sym->pos.stream].fd != -1 && valid_namespace(sym->namespace)) { + if (is_typedef(sym)) { + sym->kind = 't'; + reporter->r_symdef(sym); + continue; + } + + if (is_macro(sym)) { + sym->kind = 'd'; + reporter->r_symdef(sym); + continue; + } + + if (sym->type == SYM_STRUCT || sym->type == SYM_UNION) { + sym->ctype.base_type = sym; + examine_sym_node(sym, NULL); + continue; + } + + do_symbol(sym); + } + ); + + DO_LIST(global_scope->symbols, sym, + if (input_streams[sym->pos.stream].fd != -1 && valid_namespace(sym->namespace)) { + do_symbol(sym); + } + ); + +end: + /* Drop the tokens for this file after parsing */ + clear_token_alloc(); +} + void dissect(struct reporter *rep, struct string_list *filelist) { reporter = rep; - DO_LIST(filelist, file, do_sym_list(__sparse(file))); + DO_LIST(filelist, file, do_file(file)); } @@ -94,9 +94,9 @@ static long long get_longlong(struct expression *expr) return (value & andmask) | ormask; } -void cast_value(struct expression *expr, struct symbol *newtype, - struct expression *old, struct symbol *oldtype) +void cast_value(struct expression *expr, struct symbol *newtype, struct expression *old) { + struct symbol *oldtype = old->ctype; int old_size = oldtype->bit_size; int new_size = newtype->bit_size; long long value, mask, signmask; @@ -110,11 +110,13 @@ void cast_value(struct expression *expr, struct symbol *newtype, expr->taint = old->taint; if (old_size == new_size) { expr->value = old->value; + expr->ctype = newtype; return; } // expand it to the full "long long" value value = get_longlong(old); + expr->ctype = newtype; Int: // _Bool requires a zero test rather than truncation. @@ -153,6 +155,7 @@ Float: value = (long long)old->fvalue; expr->type = EXPR_VALUE; expr->taint = 0; + expr->ctype = newtype; goto Int; } @@ -168,6 +171,7 @@ Float: expr->fvalue = (float)expr->fvalue; } expr->type = EXPR_FVALUE; + expr->ctype = newtype; } /* Return true if constant shift size is valid */ @@ -872,7 +876,7 @@ static int expand_cast(struct expression *expr) /* Simplify normal integer casts.. */ if (target->type == EXPR_VALUE || target->type == EXPR_FVALUE) { - cast_value(expr, expr->ctype, target, target->ctype); + cast_value(expr, expr->ctype, target); return 0; } return cost + 1; diff --git a/expression.c b/expression.c index 221d7780..727e7056 100644 --- a/expression.c +++ b/expression.c @@ -427,8 +427,15 @@ struct token *primary_expression(struct token *token, struct expression **tree) case TOKEN_CHAR ... TOKEN_WIDE_CHAR_EMBEDDED_3: expr = alloc_expression(token->pos, EXPR_VALUE); expr->flags = CEF_SET_CHAR; - expr->ctype = token_type(token) < TOKEN_WIDE_CHAR ? &int_ctype : &long_ctype; get_char_constant(token, &expr->value); + + // TODO: handle 'u8', 'u' & 'U' prefixes. + if (token_type(token) < TOKEN_WIDE_CHAR) { + expr->ctype = &char_ctype; + cast_value(expr, &int_ctype, expr); + } else { + expr->ctype = wchar_ctype; + } token = token->next; break; diff --git a/expression.h b/expression.h index f733c076..8bf40d32 100644 --- a/expression.h +++ b/expression.h @@ -337,7 +337,6 @@ struct token *compound_statement(struct token *, struct statement *); #define constant_expression(token,tree) conditional_expression(token, tree) /* Cast folding of constant values.. */ -void cast_value(struct expression *expr, struct symbol *newtype, - struct expression *old, struct symbol *oldtype); +void cast_value(struct expression *expr, struct symbol *newtype, struct expression *old); #endif @@ -70,6 +70,8 @@ int dbg_postorder = 0; int dump_macro_defs = 0; int dump_macros_only = 0; +int dissect_show_all_symbols = 0; + unsigned long fdump_ir; int fhosted = 1; unsigned int fmax_errors = 100; @@ -685,6 +687,19 @@ static const struct flag mflags[] = { static char **handle_switch_m(char *arg, char **next) { + if (!strcmp(arg, "meabi") && next[1] && next[1][0] != '-') { + // clang has such an option with syntax: -meabi <arg> + // It's used by the kernel for armv7. + // GCC has the same option but with no argument. + // Parse it here to consume the possible argument. + static const char *valid[] = { "gnu", "4", "5", "default", NULL }; + int i; + for (i = 0; valid[i]; i++) { + if (!strcmp(next[1], valid[i])) + return ++next; + } + } + if (!strcmp(arg, "multiarch-dir")) { return handle_multiarch_dir(arg, next); } else { @@ -958,6 +973,9 @@ static char **handle_param(char *arg, char **next) if (!value) die("missing argument for --param option"); + if (!strcmp(value, "dissect-show-all-symbols")) + dissect_show_all_symbols = 1; + return next; } @@ -70,6 +70,8 @@ extern int dbg_postorder; extern int dump_macro_defs; extern int dump_macros_only; +extern int dissect_show_all_symbols; + extern unsigned long fdump_ir; extern int fhosted; extern unsigned int fmax_errors; @@ -903,8 +903,7 @@ static void cast_enum_list(struct symbol_list *list, struct symbol *base_type) expr->ctype = &int_ctype; continue; } - cast_value(expr, base_type, expr, ctype); - expr->ctype = base_type; + cast_value(expr, base_type, expr); } END_FOR_EACH_PTR(sym); } @@ -2329,6 +2328,11 @@ static inline struct token *case_statement(struct token *token, struct statement stmt->type = STMT_CASE; token = expect(token, ':', "after default/case"); add_case_statement(stmt); + if (match_op(token, '}')) { + warning(token->pos, "statement expected after case label"); + stmt->case_statement = alloc_statement(token->pos, STMT_NONE); + return token; + } return statement(token, &stmt->case_statement); } @@ -329,6 +329,7 @@ done: optind--; sparse_initialize(argc - optind, argv + optind, &semind_filelist); + dissect_show_all_symbols = 1; } static void parse_cmdline_rm(int argc, char **argv) @@ -165,7 +165,7 @@ static void check_byte_count(struct instruction *insn, pseudo_t count) static void check_memset(struct instruction *insn) { - check_byte_count(insn, ptr_list_nth(insn->arguments, 3)); + check_byte_count(insn, ptr_list_nth(insn->arguments, 2)); } #define check_memcpy check_memset diff --git a/test-dissect.c b/test-dissect.c index 58b3e633..65b205f8 100644 --- a/test-dissect.c +++ b/test-dissect.c @@ -57,11 +57,14 @@ static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym) show_typename(sym->ctype.base_type)); switch (sym->kind) { + case 'd': + break; case 's': if (sym->type == SYM_STRUCT || sym->type == SYM_UNION) break; goto err; - + case 't': + break; case 'f': if (sym->type != SYM_BAD && sym->ctype.base_type->type != SYM_FN) goto err; @@ -201,7 +201,7 @@ struct token { static inline struct token *containing_token(struct token **p) { - void *addr = (char *)p - ((char *)&((struct token *)0)->next - (char *)0); + void *addr = (char *)p - offsetof(struct token, next); return addr; } diff --git a/validation/builtin-objsize-self-init.c b/validation/builtin-objsize-self-init.c new file mode 100644 index 00000000..77e3da43 --- /dev/null +++ b/validation/builtin-objsize-self-init.c @@ -0,0 +1,11 @@ +static void f(void) +{ + void *param = param; + __builtin_object_size(param, 0); +} + +/* + * check-name: builtin-objsize-self-init + * check-timeout: + * check-error-end + */ diff --git a/validation/byte-count-max.c b/validation/byte-count-max.c new file mode 100644 index 00000000..0555a505 --- /dev/null +++ b/validation/byte-count-max.c @@ -0,0 +1,28 @@ +typedef unsigned long int size_t; +typedef unsigned long ulong; + +extern void *memset(void *s, int c, size_t n); +extern void *memcpy(void *dest, void *src, size_t n); +extern ulong copy_to_user(void *to, const void *from, ulong count); +extern ulong copy_from_user(void *to, const void *from, ulong count); + +static void func (char *s) +{ + char d[250000]; + + memset(d, 0, 250000); + memcpy(d, s, 250000); + copy_to_user(s, d, 250000); + copy_from_user(d, s, 250000); +} + +/* + * check-name: byte-count-max + * + * check-error-start +byte-count-max.c:13:15: warning: memset with byte count of 250000 +byte-count-max.c:14:15: warning: memcpy with byte count of 250000 +byte-count-max.c:15:21: warning: copy_to_user with byte count of 250000 +byte-count-max.c:16:23: warning: copy_from_user with byte count of 250000 + * check-error-end + */ diff --git a/validation/char-constant-signed.c b/validation/char-constant-signed.c new file mode 100644 index 00000000..be0fd5ce --- /dev/null +++ b/validation/char-constant-signed.c @@ -0,0 +1,9 @@ +int test(void) { return '\377' == -1; } + +/* + * check-name: char-constant-signed + * check-command: test-linearize -Wno-decl -fsigned-char $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/char-constant-unsigned.c b/validation/char-constant-unsigned.c new file mode 100644 index 00000000..d5642b16 --- /dev/null +++ b/validation/char-constant-unsigned.c @@ -0,0 +1,9 @@ +int test(void) { return '\377' == 255; } + +/* + * check-name: char-constant-unsigned + * check-command: test-linearize -Wno-decl -funsigned-char $file + * + * check-output-ignore + * check-output-returns: 1 + */ diff --git a/validation/label-positioning.c b/validation/label-positioning.c new file mode 100644 index 00000000..583661ca --- /dev/null +++ b/validation/label-positioning.c @@ -0,0 +1,22 @@ +extern int someval(void); + +static void func (int x) +{ + if (x > someval()) + goto end; + switch (x) { case 0: } + switch (x) { case 1 ... 9: } + switch (x) { default: } +end: +} + +/* + * check-name: label-positioning + * + * check-error-start +label-positioning.c:7:30: warning: statement expected after case label +label-positioning.c:8:36: warning: statement expected after case label +label-positioning.c:9:31: warning: statement expected after case label +label-positioning.c:11:1: warning: statement expected after label + * check-error-end + */ |