aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Documentation/release-notes/v0.6.4.rst2
-rw-r--r--builtin.c8
-rwxr-xr-xcgcc7
-rw-r--r--dissect.c61
-rw-r--r--expand.c10
-rw-r--r--expression.c9
-rw-r--r--expression.h3
-rw-r--r--options.c18
-rw-r--r--options.h2
-rw-r--r--parse.c8
-rw-r--r--semind.c1
-rw-r--r--sparse.c2
-rw-r--r--test-dissect.c5
-rw-r--r--token.h2
-rw-r--r--validation/builtin-objsize-self-init.c11
-rw-r--r--validation/byte-count-max.c28
-rw-r--r--validation/char-constant-signed.c9
-rw-r--r--validation/char-constant-unsigned.c9
-rw-r--r--validation/label-positioning.c22
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:
diff --git a/builtin.c b/builtin.c
index 8e1d2d7e..3a29c3ae 100644
--- a/builtin.c
+++ b/builtin.c
@@ -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;
diff --git a/cgcc b/cgcc
index 9c78ee63..733cadfa 100755
--- a/cgcc
+++ b/cgcc
@@ -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";
diff --git a/dissect.c b/dissect.c
index 582e8fc3..300d5ca9 100644
--- a/dissect.c
+++ b/dissect.c
@@ -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));
}
diff --git a/expand.c b/expand.c
index c4f806de..f14e7181 100644
--- a/expand.c
+++ b/expand.c
@@ -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
diff --git a/options.c b/options.c
index 6704fc8d..6ee4d878 100644
--- a/options.c
+++ b/options.c
@@ -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;
}
diff --git a/options.h b/options.h
index 0aec8764..c2a9551a 100644
--- a/options.h
+++ b/options.h
@@ -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;
diff --git a/parse.c b/parse.c
index bc1c0602..3d6fef7c 100644
--- a/parse.c
+++ b/parse.c
@@ -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);
}
diff --git a/semind.c b/semind.c
index 911fc747..ad8003ba 100644
--- a/semind.c
+++ b/semind.c
@@ -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)
diff --git a/sparse.c b/sparse.c
index 9d62d4fe..e7cc6f55 100644
--- a/sparse.c
+++ b/sparse.c
@@ -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;
diff --git a/token.h b/token.h
index bccac0e4..9000e0cb 100644
--- a/token.h
+++ b/token.h
@@ -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
+ */