diff options
41 files changed, 1000 insertions, 393 deletions
@@ -19,7 +19,7 @@ graph obfuscate sparse sparse-llvm -sindex +semind test-dissect test-inspect test-lexing diff --git a/Documentation/index.rst b/Documentation/index.rst index 737f4423..50afa558 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -26,7 +26,7 @@ Getting Sparse -------------- You can find tarballs of released versions of Sparse at -http://www.kernel.org/pub/software/devel/sparse/dist/. +https://www.kernel.org/pub/software/devel/sparse/dist/. The most recent version can be obtained directly from the Git repository with the command:: @@ -60,8 +60,8 @@ archives at https://marc.info/?l=linux-sparse. To subscribe to the list, send an email with ``subscribe linux-sparse`` in the body to ``majordomo@vger.kernel.org``. -Bugs can also be reported and tracked via the Linux kernel's bugzilla: -http://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools. +Bugs can also be reported and tracked via the `Linux kernel's bugzilla for sparse +<https://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools>`_. User documentation ------------------ @@ -157,17 +157,17 @@ ifeq ($(HAVE_SQLITE),yes) SQLITE_VERSION:=$(shell $(PKG_CONFIG) --modversion sqlite3) SQLITE_VNUMBER:=$(shell printf '%d%02d%02d' $(subst ., ,$(SQLITE_VERSION))) ifeq ($(shell expr "$(SQLITE_VNUMBER)" '>=' 32400),1) -PROGRAMS += sindex -INST_PROGRAMS += sindex -INST_MAN1 += sindex.1 -sindex-ldlibs := $(shell $(PKG_CONFIG) --libs sqlite3) -sindex-cflags := $(shell $(PKG_CONFIG) --cflags sqlite3) -sindex-cflags += -std=gnu99 +PROGRAMS += semind +INST_PROGRAMS += semind +INST_MAN1 += semind.1 +semind-ldlibs := $(shell $(PKG_CONFIG) --libs sqlite3) +semind-cflags := $(shell $(PKG_CONFIG) --cflags sqlite3) +semind-cflags += -std=gnu99 else $(warning Your SQLite3 version ($(SQLITE_VERSION)) is too old, 3.24.0 or later is required.) endif else -$(warning Your system does not have sqlite3, disabling sindex) +$(warning Your system does not have sqlite3, disabling semind) endif # Can we use gtk (needed for test-inspect) @@ -355,6 +355,62 @@ static struct symbol_op overflow_p_op = { }; +static int eval_sync_compare_and_swap(struct expression *expr) +{ + struct symbol_list *types = NULL; + struct symbol *ctype = NULL; + struct expression *arg; + int n = 0; + + /* the first arg is a pointer type; we'd already verified that */ + FOR_EACH_PTR(expr->args, arg) { + struct symbol *t = arg->ctype; + + if (!t) + return 0; + + // 2nd & 3rd args must be a basic integer type or a pointer + // 1st arg must be a pointer to such a type. + if (++n == 1) { + if (t->type == SYM_NODE) + t = t->ctype.base_type; + if (!t) + return 0; + if (t->type != SYM_PTR) + goto err; + t = t->ctype.base_type; + if (!t) + return 0; + if (t->type == SYM_NODE) + t = t->ctype.base_type; + if (!t) + return 0; + if (t->type != SYM_PTR && t->ctype.base_type != &int_type) + goto err; + ctype = t; + add_ptr_list(&types, arg->ctype); + } else { + add_ptr_list(&types, ctype); + } + } END_FOR_EACH_PTR(arg); + + if (!expr->ctype) // __sync_val_compare_and_swap() + expr->ctype = ctype; + return evaluate_arguments(types, expr->args); + +err: + sparse_error(arg->pos, "invalid type for argument %d:", n); + info(arg->pos, " %s", show_typename(arg->ctype)); + expr->ctype = &bad_ctype; + return 0; +} + +static struct symbol_op sync_compare_and_swap_op = { + .args = args_triadic, + .evaluate = eval_sync_compare_and_swap, +}; + + /* * Builtin functions */ @@ -548,7 +604,7 @@ static const struct builtin_fn builtins_common[] = { { "__sync_add_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { "__sync_and_and_fetch", &int_ctype, 1, { &ptr_ctype }}, - { "__sync_bool_compare_and_swap", &int_ctype, 1, { &ptr_ctype }}, + { "__sync_bool_compare_and_swap", &bool_ctype, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op}, { "__sync_fetch_and_add", &int_ctype, 1, { &ptr_ctype }}, { "__sync_fetch_and_and", &int_ctype, 1, { &ptr_ctype }}, { "__sync_fetch_and_nand", &int_ctype, 1, { &ptr_ctype }}, @@ -561,7 +617,7 @@ static const struct builtin_fn builtins_common[] = { { "__sync_or_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { "__sync_sub_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { "__sync_synchronize", &void_ctype, 0 }, - { "__sync_val_compare_and_swap", &int_ctype, 1, { &ptr_ctype }}, + { "__sync_val_compare_and_swap", NULL, 1, { &ptr_ctype }, .op = &sync_compare_and_swap_op }, { "__sync_xor_and_fetch", &int_ctype, 1, { &ptr_ctype }}, { } @@ -204,9 +204,9 @@ static void examine_sym_node(struct symbol *node, struct symbol *parent) struct ident *name = node->ident; struct symbol *base, *dctx; - if (node->examined) + if (node->visited) return; - node->examined = 1; + node->visited = 1; node->kind = 'v'; while ((base = node->ctype.base_type) != NULL) @@ -228,9 +228,9 @@ static void examine_sym_node(struct symbol *node, struct symbol *parent) break; case SYM_STRUCT: case SYM_UNION: //case SYM_ENUM: - if (base->evaluated) + if (base->inspected) return; - base->evaluated = 1; + base->inspected = 1; base->kind = 's'; if (!base->symbol_list) @@ -471,6 +471,17 @@ again: } while ((expr = expr->down)); } + break; case EXPR_GENERIC: { + struct type_expression *map; + + do_expression(U_VOID, expr->control); + + for (map = expr->map; map; map = map->next) + ret = do_expression(mode, map->expr); + if (expr->def) + ret = do_expression(mode, expr->def); + } + break; case EXPR_SYMBOL: ret = report_symbol(mode, expr); } @@ -102,9 +102,10 @@ static struct symbol *evaluate_string(struct expression *expr) struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL); struct expression *initstr = alloc_expression(expr->pos, EXPR_STRING); unsigned int length = expr->string->length; + struct symbol *char_type = expr->wide ? wchar_ctype : &char_ctype; sym->array_size = alloc_const_expression(expr->pos, length); - sym->bit_size = bytes_to_bits(length); + sym->bit_size = length * char_type->bit_size; sym->ctype.alignment = 1; sym->string = 1; sym->ctype.modifiers = MOD_STATIC; @@ -117,10 +118,10 @@ static struct symbol *evaluate_string(struct expression *expr) initstr->string = expr->string; array->array_size = sym->array_size; - array->bit_size = bytes_to_bits(length); - array->ctype.alignment = 1; + array->bit_size = sym->bit_size; + array->ctype.alignment = char_type->ctype.alignment; array->ctype.modifiers = MOD_STATIC; - array->ctype.base_type = &char_ctype; + array->ctype.base_type = char_type; array->examined = 1; array->evaluated = 1; @@ -405,7 +406,10 @@ static inline int is_string_type(struct symbol *type) { if (type->type == SYM_NODE) type = type->ctype.base_type; - return type->type == SYM_ARRAY && is_byte_type(type->ctype.base_type); + if (type->type != SYM_ARRAY) + return 0; + type = type->ctype.base_type; + return is_byte_type(type) || is_wchar_type(type); } static struct symbol *bad_expr_type(struct expression *expr) @@ -1342,8 +1346,17 @@ static int evaluate_assign_op(struct expression *expr) return 1; } else if (op == SPECIAL_SHR_ASSIGN || op == SPECIAL_SHL_ASSIGN) { // shifts do integer promotions, but that's it. + unrestrict(expr->left, tclass, &t); + target = integer_promotion(t); + unrestrict(expr->right, sclass, &s); - target = integer_promotion(s); + source = integer_promotion(s); + expr->right = cast_to(expr->right, source); + + // both gcc & clang seems to do this, so ... + if (target->bit_size > source->bit_size) + expr->right = cast_to(expr->right, &uint_ctype); + goto Cast; } else if (!(sclass & TYPE_RESTRICT)) goto usual; @@ -2333,14 +2346,13 @@ static struct symbol *evaluate_alignof(struct expression *expr) return size_t_ctype; } -static int evaluate_arguments(struct symbol *fn, struct expression_list *head) +int evaluate_arguments(struct symbol_list *argtypes, struct expression_list *head) { struct expression *expr; - struct symbol_list *argument_types = fn->arguments; struct symbol *argtype; int i = 1; - PREPARE_PTR_LIST(argument_types, argtype); + PREPARE_PTR_LIST(argtypes, argtype); FOR_EACH_PTR (head, expr) { struct expression **p = THIS_ADDRESS(expr); struct symbol *ctype, *target; @@ -2760,7 +2772,6 @@ static struct expression *handle_scalar(struct expression *e, int nested) static int handle_initializer(struct expression **ep, int nested, int class, struct symbol *ctype, unsigned long mods) { - int is_string = is_string_type(ctype); struct expression *e = *ep, *p; struct symbol *type; @@ -2794,7 +2805,7 @@ static int handle_initializer(struct expression **ep, int nested, * pathologies, so we don't need anything fancy here. */ if (e->type == EXPR_INITIALIZER) { - if (is_string) { + if (is_string_type(ctype)) { struct expression *v = NULL; int count = 0; @@ -2815,7 +2826,7 @@ static int handle_initializer(struct expression **ep, int nested, /* string */ if (is_string_literal(&e)) { /* either we are doing array of char, or we'll have to dig in */ - if (is_string) { + if (is_string_type(ctype)) { *ep = e; goto String; } @@ -2840,10 +2851,12 @@ String: *p = *e; type = evaluate_expression(p); if (ctype->bit_size != -1) { - if (ctype->bit_size + bits_in_char < type->bit_size) + struct symbol *char_type = e->wide ? wchar_ctype : &char_ctype; + unsigned int size_with_null = ctype->bit_size + char_type->bit_size; + if (size_with_null < type->bit_size) warning(e->pos, "too long initializer-string for array of char"); - else if (Winit_cstring && ctype->bit_size + bits_in_char == type->bit_size) { + else if (Winit_cstring && size_with_null == type->bit_size) { warning(e->pos, "too long initializer-string for array of char(no space for nul char)"); } @@ -3149,7 +3162,7 @@ static struct symbol *evaluate_call(struct expression *expr) if (!sym->op->args(expr)) return NULL; } else { - if (!evaluate_arguments(ctype, arglist)) + if (!evaluate_arguments(ctype->arguments, arglist)) return NULL; args = expression_list_size(expr->args); fnargs = symbol_list_size(ctype->arguments); @@ -3544,7 +3557,7 @@ static struct symbol *evaluate_return_expression(struct statement *stmt) fntype = current_fn->ctype.base_type; rettype = fntype->ctype.base_type; if (!rettype || rettype == &void_ctype) { - if (expr && expr->ctype != &void_ctype) + if (expr && !is_void_type(expr->ctype)) expression_error(expr, "return expression in %s function", rettype?"void":"typeless"); if (expr && Wreturn_void) warning(stmt->pos, "returning void-valued expression"); @@ -2,6 +2,7 @@ #define EVALUATE_H struct expression; +struct expression_list; struct statement; struct symbol; struct symbol_list; @@ -25,4 +26,10 @@ struct symbol *evaluate_statement(struct statement *stmt); // @list: the list of the symbol to be evaluated void evaluate_symbol_list(struct symbol_list *list); +/// +// evaluate the arguments of a function +// @argtypes: the list of the types in the prototype +// @args: the list of the effective arguments +int evaluate_arguments(struct symbol_list *argtypes, struct expression_list *args); + #endif @@ -170,22 +170,6 @@ Float: expr->type = EXPR_FVALUE; } -static void warn_shift_count(struct expression *expr, struct symbol *ctype, long long count) -{ - if (count < 0) { - if (!Wshift_count_negative) - return; - warning(expr->pos, "shift count is negative (%lld)", count); - return; - } - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - - if (!Wshift_count_overflow) - return; - warning(expr->pos, "shift too big (%llu) for type %s", count, show_typename(ctype)); -} - /* Return true if constant shift size is valid */ static bool check_shift_count(struct expression *expr, struct expression *right) { @@ -194,8 +178,6 @@ static bool check_shift_count(struct expression *expr, struct expression *right) if (count >= 0 && count < ctype->bit_size) return true; - if (!conservative) - warn_shift_count(expr, ctype, count); return false; } diff --git a/expression.h b/expression.h index 07fe8502..3e9e9d85 100644 --- a/expression.h +++ b/expression.h @@ -261,7 +261,6 @@ struct expression { struct expression *control; struct expression *def; struct type_expression *map; - struct expression *result; }; }; }; @@ -274,6 +274,14 @@ static struct expression * copy_expression(struct expression *expr) } break; } + case EXPR_GENERIC: + expr = dup_expression(expr); + expr->control = copy_expression(expr->control); + if (!evaluate_expression(expr)) + return NULL; + expr = copy_expression(expr); + break; + default: warning(expr->pos, "trying to copy expression type %d", expr->type); } @@ -351,7 +351,7 @@ static struct symbol_list *sparse_file(const char *filename) base_filename = filename; // Tokenize the input stream - token = tokenize(filename, fd, -1, NULL, includepath); + token = tokenize(NULL, filename, fd, NULL, includepath); close(fd); return sparse_tokenstream(token); @@ -383,6 +383,8 @@ struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list char **args; struct symbol_list *list; + base_filename = "command-line"; + // Initialize symbol stream first, so that we can add defines etc init_symbols(); @@ -44,6 +44,10 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) #endif +#ifndef PATH_MAX +#define PATH_MAX 4096 // Hurd doesn't define this +#endif + struct position { unsigned int type:6, diff --git a/linearize.c b/linearize.c index 49274681..5a8e7497 100644 --- a/linearize.c +++ b/linearize.c @@ -2468,6 +2468,49 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm return VOID; } +static void check_tainted_insn(struct instruction *insn) +{ + unsigned long long uval; + long long sval; + pseudo_t src2; + + switch (insn->opcode) { + case OP_DIVU: case OP_DIVS: + case OP_MODU: case OP_MODS: + if (insn->src2 == value_pseudo(0)) + warning(insn->pos, "divide by zero"); + break; + case OP_SHL: case OP_LSR: case OP_ASR: + src2 = insn->src2; + if (src2->type != PSEUDO_VAL) + break; + uval = src2->value; + if (uval < insn->size) + break; + sval = sign_extend(uval, insn->size); + if (Wshift_count_negative && sval < 0) + warning(insn->pos, "shift count is negative (%lld)", sval); + else if (Wshift_count_overflow) + warning(insn->pos, "shift too big (%llu) for type %s", uval, show_typename(insn->type)); + } +} + +/// +// issue warnings after all possible DCE +static void late_warnings(struct entrypoint *ep) +{ + struct basic_block *bb; + FOR_EACH_PTR(ep->bbs, bb) { + struct instruction *insn; + FOR_EACH_PTR(bb->insns, insn) { + if (!insn->bb) + continue; + if (insn->tainted) + check_tainted_insn(insn); + } END_FOR_EACH_PTR(insn); + } END_FOR_EACH_PTR(bb); +} + static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type) { struct statement *stmt = base_type->stmt; @@ -2514,6 +2557,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t add_one_insn(ep, ret); optimize(ep); + late_warnings(ep); return ep; } @@ -782,6 +782,12 @@ static char **handle_switch_s(const char *arg, char **next) static char **handle_switch_U(char *arg, char **next) { const char *name = arg + 1; + + if (*name == '\0') { + name = *++next; + if (!name) + die("argument to `-U' is missing"); + } add_pre_buffer("#undef %s\n", name); return next; } @@ -171,7 +171,7 @@ static struct symbol_op register_op = { }; static struct symbol_op static_op = { - .type = KW_MODIFIER, + .type = KW_MODIFIER|KW_STATIC, .declarator = static_specifier, }; @@ -678,24 +678,6 @@ static void fn_local_symbol(struct symbol *sym) add_symbol(function_symbol_list, sym); } -static int SENTINEL_ATTR match_idents(struct token *token, ...) -{ - va_list args; - struct ident * next; - - if (token_type(token) != TOKEN_IDENT) - return 0; - - va_start(args, token); - do { - next = va_arg(args, struct ident *); - } while (next && token->ident != next); - va_end(args); - - return next && token->ident == next; -} - - struct statement *alloc_statement(struct position pos, int type) { struct statement *stmt = __alloc_statement(0); @@ -1362,18 +1344,8 @@ static struct token *attribute_specifier(struct token *token, struct decl_state token = expect(token, '(', "after attribute"); token = expect(token, '(', "after attribute"); - for (;;) { - struct ident *attribute_name; - struct symbol *attr; - - if (eof_token(token)) - break; - if (match_op(token, ';')) - break; - if (token_type(token) != TOKEN_IDENT) - break; - attribute_name = token->ident; - attr = lookup_keyword(attribute_name, NS_KEYWORD); + while (token_type(token) == TOKEN_IDENT) { + struct symbol *attr = lookup_keyword(token->ident, NS_KEYWORD); if (attr && attr->op->attribute) token = attr->op->attribute(token->next, attr, ctx); else @@ -1721,29 +1693,26 @@ static struct token *declaration_specifiers(struct token *token, struct decl_sta return token; } -static struct token *abstract_array_static_declarator(struct token *token, int *has_static) -{ - while (token->ident == &static_ident) { - if (*has_static) - sparse_error(token->pos, "duplicate array static declarator"); - - *has_static = 1; - token = token->next; - } - return token; - -} - static struct token *abstract_array_declarator(struct token *token, struct symbol *sym) { struct expression *expr = NULL; int has_static = 0; - token = abstract_array_static_declarator(token, &has_static); - - if (match_idents(token, &restrict_ident, &__restrict_ident, &__restrict___ident, NULL)) - token = abstract_array_static_declarator(token->next, &has_static); - token = parse_expression(token, &expr); + while (token_type(token) == TOKEN_IDENT) { + struct symbol *sym = lookup_keyword(token->ident, NS_TYPEDEF); + if (!sym || !(sym->op->type & (KW_STATIC|KW_QUALIFIER))) + break; + if (has_static && (sym->op->type & KW_STATIC)) + sparse_error(token->pos, "duplicate array static declarator"); + has_static |= (sym->op->type & KW_STATIC); + token = token->next; + } + if (match_op(token, '*') && match_op(token->next, ']')) { + // FIXME: '[*]' is treated like '[]' + token = token->next; + } else { + token = assignment_expression(token, &expr); + } sym->array_size = expr; return token; } @@ -1784,13 +1753,7 @@ static struct token *skip_attributes(struct token *token) break; token = expect(token->next, '(', "after attribute"); token = expect(token, '(', "after attribute"); - for (;;) { - if (eof_token(token)) - break; - if (match_op(token, ';')) - break; - if (token_type(token) != TOKEN_IDENT) - break; + while (token_type(token) == TOKEN_IDENT) { token = skip_attribute(token); if (!match_op(token, ',')) break; diff --git a/pre-process.c b/pre-process.c index 6f4bf897..7a1478f6 100644 --- a/pre-process.c +++ b/pre-process.c @@ -890,10 +890,6 @@ static void set_stream_include_path(struct stream *stream) includepath[0] = path; } -#ifndef PATH_MAX -#define PATH_MAX 4096 // for Hurd where it's not defined -#endif - static int try_include(struct position pos, const char *path, const char *filename, int flen, struct token **where, const char **next_path) { int fd; @@ -911,7 +907,7 @@ static int try_include(struct position pos, const char *path, const char *filena fd = open(fullname, O_RDONLY); if (fd >= 0) { char *streamname = xmemdup(fullname, plen + flen); - *where = tokenize(streamname, fd, pos.stream, *where, next_path); + *where = tokenize(&pos, streamname, fd, *where, next_path); close(fd); return 1; } @@ -2091,7 +2087,7 @@ static void create_arglist(struct symbol *sym, int count) static void init_preprocessor(void) { int i; - int stream = init_stream("preprocessor", -1, includepath, -1); + int stream = init_stream(NULL, "preprocessor", -1, includepath); static struct { const char *name; int (*handler)(struct stream *, struct token **, struct token *); @@ -1,27 +1,27 @@ .\" Sindex manpage by Alexey Gladkov -.TH sindex "1" +.TH semind "1" . .SH NAME -sindex \- Semantic Indexer for C +semind \- Semantic Indexer for C . .SH SYNOPSIS -.B sindex +.B semind [\fIoptions\fR] .br -.B sindex +.B semind [\fIoptions\fR] \fIadd\fR [\fIcommand options\fR] [\fI--\fR] [\fIcompiler options\fR] [\fIfiles...\fR] .br -.B sindex +.B semind [\fIoptions\fR] \fIrm\fR [\fIcommand options\fR] \fIpattern\fR .br -.B sindex +.B semind [\fIoptions\fR] \fIsearch\fR [\fIcommand options\fR] [\fIpattern\fR] .br -.B sindex [\fIoptions\fR] \fIsearch\fR [\fIcommand options\fR] (\fI-e\fR|\fI-l\fR) \fIfilename\fR:\fIlinenr\fR:\fIcolumn\fR +.B semind [\fIoptions\fR] \fIsearch\fR [\fIcommand options\fR] (\fI-e\fR|\fI-l\fR) \fIfilename\fR:\fIlinenr\fR:\fIcolumn\fR .br .SH DESCRIPTION .P -sindex is the simple to use cscope-like tool based on sparse/dissect. Unlike +semind is the simple to use cscope-like tool based on sparse/dissect. Unlike cscope it runs after pre-processor and thus it can't index the code filtered out by ifdef's, but otoh it understands how the symbol is used and it can track the usage of struct members. @@ -44,7 +44,7 @@ wildcard pattern. .SH COMMON OPTIONS .TP \fB-D\fR, \fB--database=FILE\fR -specify database file (default: ./sindex.sqlite). +specify database file (default: ./semind.sqlite). .TP \fB-v\fR, \fB--verbose\fR show information about what is being done. @@ -128,8 +128,8 @@ struct member . .SH MODE The \fBMODE\fR is dumped as a 3-letter string. The first letter denotes address -of part, 2-nd - access by value, 3-rd - access by pointer. A special value -\'\fIdef\fR\' means a symbol definition. +of part, 2-nd - access by value, 3-rd - access by pointer. A special +value '\fIdef\fR' means a symbol definition. .TP \fBr\fR read @@ -144,7 +144,7 @@ read and write .BR sparse (1) . .SH HOMEPAGE -http://www.kernel.org/pub/software/devel/sparse/ +https://sparse.docs.kernel.org . .SH MAILING LIST linux-sparse@vger.kernel.org @@ -1,5 +1,5 @@ /* - * sindex - semantic indexer for C. + * semind - semantic indexer for C. * * Copyright (C) 2020 Alexey Gladkov */ @@ -23,44 +23,44 @@ #define U_DEF (0x100 << U_SHIFT) #define SINDEX_DATABASE_VERSION 1 -#define message(fmt, ...) sindex_error(0, 0, (fmt), ##__VA_ARGS__) +#define message(fmt, ...) semind_error(0, 0, (fmt), ##__VA_ARGS__) static const char *progname; -static const char *sindex_command = NULL; +static const char *semind_command = NULL; // common options -static const char *sindex_dbfile = "sindex.sqlite"; -static int sindex_verbose = 0; +static const char *semind_dbfile = "semind.sqlite"; +static int semind_verbose = 0; static char cwd[PATH_MAX]; static size_t n_cwd; // 'add' command options -static struct string_list *sindex_filelist = NULL; -static int sindex_include_local_syms = 0; +static struct string_list *semind_filelist = NULL; +static int semind_include_local_syms = 0; -struct sindex_streams { +struct semind_streams { sqlite3_int64 id; }; -static struct sindex_streams *sindex_streams = NULL; -static int sindex_streams_nr = 0; +static struct semind_streams *semind_streams = NULL; +static int semind_streams_nr = 0; // 'search' command options -static int sindex_search_modmask; -static int sindex_search_modmask_defined = 0; -static int sindex_search_kind = 0; -static char *sindex_search_path = NULL; -static char *sindex_search_symbol = NULL; -static const char *sindex_search_format = "(%m) %f\t%l\t%c\t%C\t%s"; +static int semind_search_modmask; +static int semind_search_modmask_defined = 0; +static int semind_search_kind = 0; +static char *semind_search_path = NULL; +static char *semind_search_symbol = NULL; +static const char *semind_search_format = "(%m) %f\t%l\t%c\t%C\t%s"; #define EXPLAIN_LOCATION 1 #define USAGE_BY_LOCATION 2 -static int sindex_search_by_location; -static char *sindex_search_filename; -static int sindex_search_line; -static int sindex_search_column; +static int semind_search_by_location; +static char *semind_search_filename; +static int semind_search_line; +static int semind_search_column; -static sqlite3 *sindex_db = NULL; +static sqlite3 *semind_db = NULL; static sqlite3_stmt *lock_stmt = NULL; static sqlite3_stmt *unlock_stmt = NULL; static sqlite3_stmt *insert_rec_stmt = NULL; @@ -77,9 +77,9 @@ struct command { static void show_usage(void) { - if (sindex_command) + if (semind_command) printf("Try '%s %s --help' for more information.\n", - progname, sindex_command); + progname, semind_command); else printf("Try '%s --help' for more information.\n", progname); @@ -101,15 +101,17 @@ static void show_help(int ret) "\n" "Options:\n" " -D, --database=FILE Specify database file (default: %2$s);\n" + " -B, --basedir=DIR Define project top directory (default is the current directory);\n" " -v, --verbose Show information about what is being done;\n" " -h, --help Show this text and exit.\n" "\n" "Environment:\n" " SINDEX_DATABASE Database file location.\n" + " SINDEX_BASEDIR Project top directory.\n" "\n" "Report bugs to authors.\n" "\n", - progname, sindex_dbfile); + progname, semind_dbfile); exit(ret); } @@ -125,9 +127,6 @@ static void show_help_add(int ret) " -v, --verbose Show information about what is being done;\n" " -h, --help Show this text and exit.\n" "\n" - "Environment:\n" - " SINDEX_BASEDIRE Project top directory.\n" - "\n" "Report bugs to authors.\n" "\n", progname); @@ -180,17 +179,17 @@ static void show_help_search(int ret) exit(ret); } -static void sindex_print_progname(void) +static void semind_print_progname(void) { fprintf(stderr, "%s: ", progname); - if (sindex_command) - fprintf(stderr, "%s: ", sindex_command); + if (semind_command) + fprintf(stderr, "%s: ", semind_command); } -static void sindex_error(int status, int errnum, const char *fmt, ...) +static void semind_error(int status, int errnum, const char *fmt, ...) { va_list ap; - sindex_print_progname(); + semind_print_progname(); va_start(ap, fmt); vfprintf(stderr, fmt, ap); @@ -210,10 +209,10 @@ static void set_search_modmask(const char *v) size_t n = strlen(v); if (n != 1 && n != 3) - sindex_error(1, 0, "the length of mode value must be 1 or 3: %s", v); + semind_error(1, 0, "the length of mode value must be 1 or 3: %s", v); - sindex_search_modmask_defined = 1; - sindex_search_modmask = 0; + semind_search_modmask_defined = 1; + semind_search_modmask = 0; if (n == 1) { switch (v[0]) { @@ -221,10 +220,10 @@ static void set_search_modmask(const char *v) case 'w': v = "ww-"; break; case 'm': v = "mmm"; break; case '-': v = "---"; break; - default: sindex_error(1, 0, "unknown modificator: %s", v); + default: semind_error(1, 0, "unknown modificator: %s", v); } } else if (!strcmp(v, "def")) { - sindex_search_modmask = U_DEF; + semind_search_modmask = U_DEF; return; } @@ -236,11 +235,11 @@ static void set_search_modmask(const char *v) for (int i = 0; i < 3; i++) { switch (v[i]) { - case 'r': sindex_search_modmask |= modes[i * 3]; break; - case 'w': sindex_search_modmask |= modes[i * 3 + 1]; break; - case 'm': sindex_search_modmask |= modes[i * 3 + 2]; break; + case 'r': semind_search_modmask |= modes[i * 3]; break; + case 'w': semind_search_modmask |= modes[i * 3 + 1]; break; + case 'm': semind_search_modmask |= modes[i * 3 + 2]; break; case '-': break; - default: sindex_error(1, 0, + default: semind_error(1, 0, "unknown modificator in the mode value" " (`r', `w', `m' or `-' expected): %c", v[i]); } @@ -251,23 +250,28 @@ static void parse_cmdline(int argc, char **argv) { static const struct option long_options[] = { { "database", required_argument, NULL, 'D' }, + { "basedir", required_argument, NULL, 'B' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { NULL } }; int c; + char *basedir = getenv("SINDEX_BASEDIR"); char *env; if ((env = getenv("SINDEX_DATABASE")) != NULL) - sindex_dbfile = env; + semind_dbfile = env; - while ((c = getopt_long(argc, argv, "+D:vh", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "+B:D:vh", long_options, NULL)) != -1) { switch (c) { case 'D': - sindex_dbfile = optarg; + semind_dbfile = optarg; + break; + case 'B': + basedir = optarg; break; case 'v': - sindex_verbose++; + semind_verbose++; break; case 'h': show_help(0); @@ -278,6 +282,12 @@ static void parse_cmdline(int argc, char **argv) message("command required"); show_usage(); } + + if (basedir) { + if (!realpath(basedir, cwd)) + semind_error(1, errno, "unable to get project base directory"); + n_cwd = strlen(cwd); + } } static void parse_cmdline_add(int argc, char **argv) @@ -295,10 +305,10 @@ static void parse_cmdline_add(int argc, char **argv) while ((c = getopt_long(argc, argv, "+vh", long_options, NULL)) != -1) { switch (c) { case 1: - sindex_include_local_syms = 1; + semind_include_local_syms = 1; break; case 'v': - sindex_verbose++; + semind_verbose++; break; case 'h': show_help_add(0); @@ -318,7 +328,7 @@ done: // step back since sparse_initialize will ignore argv[0]. optind--; - sparse_initialize(argc - optind, argv + optind, &sindex_filelist); + sparse_initialize(argc - optind, argv + optind, &semind_filelist); } static void parse_cmdline_rm(int argc, char **argv) @@ -333,7 +343,7 @@ static void parse_cmdline_rm(int argc, char **argv) while ((c = getopt_long(argc, argv, "+vh", long_options, NULL)) != -1) { switch (c) { case 'v': - sindex_verbose++; + semind_verbose++; break; case 'h': show_help_rm(0); @@ -364,36 +374,36 @@ static void parse_cmdline_search(int argc, char **argv) while ((c = getopt_long(argc, argv, "+ef:m:k:p:lvh", long_options, NULL)) != -1) { switch (c) { case 'e': - sindex_search_by_location = EXPLAIN_LOCATION; + semind_search_by_location = EXPLAIN_LOCATION; break; case 'l': - sindex_search_by_location = USAGE_BY_LOCATION; + semind_search_by_location = USAGE_BY_LOCATION; break; case 'f': - sindex_search_format = optarg; + semind_search_format = optarg; break; case 'm': set_search_modmask(optarg); break; case 'k': - sindex_search_kind = tolower(optarg[0]); + semind_search_kind = tolower(optarg[0]); break; case 'p': - sindex_search_path = optarg; + semind_search_path = optarg; break; case 'v': - sindex_verbose++; + semind_verbose++; break; case 'h': show_help_search(0); } } - if (sindex_search_by_location) { + if (semind_search_by_location) { char *str; if (optind == argc) - sindex_error(1, 0, "one argument required"); + semind_error(1, 0, "one argument required"); str = argv[optind]; @@ -404,18 +414,18 @@ static void parse_cmdline_search(int argc, char **argv) *ptr++ = '\0'; if (*str != '\0') { - if (!sindex_search_filename) { - sindex_search_filename = str; - } else if (!sindex_search_line) { - sindex_search_line = atoi(str); - } else if (!sindex_search_column) { - sindex_search_column = atoi(str); + if (!semind_search_filename) { + semind_search_filename = str; + } else if (!semind_search_line) { + semind_search_line = atoi(str); + } else if (!semind_search_column) { + semind_search_column = atoi(str); } } str = ptr; } } else if (optind < argc) - sindex_search_symbol = argv[optind++]; + semind_search_symbol = argv[optind++]; } static int query_appendf(sqlite3_str *query, const char *fmt, ...) @@ -442,22 +452,22 @@ static int query_appendf(sqlite3_str *query, const char *fmt, ...) static inline void sqlite_bind_text(sqlite3_stmt *stmt, const char *field, const char *var, int len) { if (sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, field), var, len, SQLITE_STATIC) != SQLITE_OK) - sindex_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(sindex_db)); + semind_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(semind_db)); } static inline void sqlite_bind_int64(sqlite3_stmt *stmt, const char *field, long long var) { if (sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, field), var) != SQLITE_OK) - sindex_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(sindex_db)); + semind_error(1, 0, "unable to bind value for %s: %s", field, sqlite3_errmsg(semind_db)); } static inline void sqlite_prepare(const char *sql, sqlite3_stmt **stmt) { int ret; do { - ret = sqlite3_prepare_v2(sindex_db, sql, -1, stmt, NULL); + ret = sqlite3_prepare_v2(semind_db, sql, -1, stmt, NULL); if (ret != SQLITE_OK && ret != SQLITE_BUSY) - sindex_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(sindex_db), sql); + semind_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(semind_db), sql); } while (ret == SQLITE_BUSY); } @@ -465,9 +475,9 @@ static inline void sqlite_prepare_persistent(const char *sql, sqlite3_stmt **stm { int ret; do { - ret = sqlite3_prepare_v3(sindex_db, sql, -1, SQLITE_PREPARE_PERSISTENT, stmt, NULL); + ret = sqlite3_prepare_v3(semind_db, sql, -1, SQLITE_PREPARE_PERSISTENT, stmt, NULL); if (ret != SQLITE_OK && ret != SQLITE_BUSY) - sindex_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(sindex_db), sql); + semind_error(1, 0, "unable to prepare query: %s: %s", sqlite3_errmsg(semind_db), sql); } while (ret == SQLITE_BUSY); } @@ -484,7 +494,7 @@ static int sqlite_run(sqlite3_stmt *stmt) { int ret = sqlite3_step(stmt); if (ret != SQLITE_DONE && ret != SQLITE_ROW) - sindex_error(1, 0, "unable to process query: %s: %s", sqlite3_errmsg(sindex_db), sqlite3_sql(stmt)); + semind_error(1, 0, "unable to process query: %s: %s", sqlite3_errmsg(semind_db), sqlite3_sql(stmt)); return ret; } @@ -512,7 +522,7 @@ static sqlite3_int64 get_db_version(void) static void set_db_version(void) { char *sql; - sqlite3_str *query = sqlite3_str_new(sindex_db); + sqlite3_str *query = sqlite3_str_new(semind_db); if (query_appendf(query, "PRAGMA user_version = %d", SINDEX_DATABASE_VERSION) < 0) exit(1); @@ -526,7 +536,7 @@ static void open_temp_database(void) { static const char *database_schema[] = { "ATTACH ':memory:' AS tempdb", - "CREATE TABLE tempdb.sindex (" + "CREATE TABLE tempdb.semind (" " file INTEGER NOT NULL," " line INTEGER NOT NULL," " column INTEGER NOT NULL," @@ -550,7 +560,7 @@ static void open_database(const char *filename, int flags) " name TEXT UNIQUE NOT NULL," " mtime INTEGER NOT NULL" ")", - "CREATE TABLE sindex (" + "CREATE TABLE semind (" " file INTEGER NOT NULL REFERENCES file(id) ON DELETE CASCADE," " line INTEGER NOT NULL," " column INTEGER NOT NULL," @@ -559,15 +569,15 @@ static void open_database(const char *filename, int flags) " context TEXT," " mode INTEGER NOT NULL" ")", - "CREATE UNIQUE INDEX sindex_0 ON sindex (symbol, kind, mode, file, line, column)", - "CREATE INDEX sindex_1 ON sindex (file)", + "CREATE UNIQUE INDEX semind_0 ON semind (symbol, kind, mode, file, line, column)", + "CREATE INDEX semind_1 ON semind (file)", NULL, }; int exists = !access(filename, R_OK); - if (sqlite3_open_v2(filename, &sindex_db, flags, NULL) != SQLITE_OK) - sindex_error(1, 0, "unable to open database: %s: %s", filename, sqlite3_errmsg(sindex_db)); + if (sqlite3_open_v2(filename, &semind_db, flags, NULL) != SQLITE_OK) + semind_error(1, 0, "unable to open database: %s: %s", filename, sqlite3_errmsg(semind_db)); sqlite_command("PRAGMA journal_mode = WAL"); sqlite_command("PRAGMA synchronous = OFF"); @@ -577,7 +587,7 @@ static void open_database(const char *filename, int flags) if (exists) { if (get_db_version() < SINDEX_DATABASE_VERSION) - sindex_error(1, 0, "%s: Database too old. Please rebuild it.", filename); + semind_error(1, 0, "%s: Database too old. Please rebuild it.", filename); return; } @@ -617,16 +627,16 @@ static void insert_record(struct index_record *rec) static void update_stream(void) { - if (sindex_streams_nr >= input_stream_nr) + if (semind_streams_nr >= input_stream_nr) return; - sindex_streams = realloc(sindex_streams, input_stream_nr * sizeof(struct sindex_streams)); - if (!sindex_streams) - sindex_error(1, errno, "realloc"); + semind_streams = realloc(semind_streams, input_stream_nr * sizeof(struct semind_streams)); + if (!semind_streams) + semind_error(1, errno, "realloc"); sqlite_run(lock_stmt); - for (int i = sindex_streams_nr; i < input_stream_nr; i++) { + for (int i = semind_streams_nr; i < input_stream_nr; i++) { struct stat st; const char *filename; char fullname[PATH_MAX]; @@ -637,26 +647,26 @@ static void update_stream(void) * FIXME: Files in the input_streams may be duplicated. */ if (stat(input_streams[i].name, &st) < 0) - sindex_error(1, errno, "stat: %s", input_streams[i].name); + semind_error(1, errno, "stat: %s", input_streams[i].name); cur_mtime = st.st_mtime; if (!realpath(input_streams[i].name, fullname)) - sindex_error(1, errno, "realpath: %s", input_streams[i].name); + semind_error(1, errno, "realpath: %s", input_streams[i].name); if (!strncmp(fullname, cwd, n_cwd) && fullname[n_cwd] == '/') { filename = fullname + n_cwd + 1; - sindex_streams[i].id = 0; + semind_streams[i].id = 0; } else { - sindex_streams[i].id = -1; + semind_streams[i].id = -1; continue; } } else { - sindex_streams[i].id = -1; + semind_streams[i].id = -1; continue; } - if (sindex_verbose > 1) + if (semind_verbose > 1) message("filename: %s", filename); sqlite_bind_text(select_file_stmt, "@name", filename, -1); @@ -664,7 +674,7 @@ static void update_stream(void) if (sqlite_run(select_file_stmt) == SQLITE_ROW) { sqlite3_int64 old_mtime; - sindex_streams[i].id = sqlite3_column_int64(select_file_stmt, 0); + semind_streams[i].id = sqlite3_column_int64(select_file_stmt, 0); old_mtime = sqlite3_column_int64(select_file_stmt, 1); sqlite_reset_stmt(select_file_stmt); @@ -684,12 +694,12 @@ static void update_stream(void) sqlite_run(insert_file_stmt); sqlite_reset_stmt(insert_file_stmt); - sindex_streams[i].id = sqlite3_last_insert_rowid(sindex_db); + semind_streams[i].id = sqlite3_last_insert_rowid(semind_db); } sqlite_run(unlock_stmt); - sindex_streams_nr = input_stream_nr; + semind_streams_nr = input_stream_nr; } static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym) @@ -700,10 +710,10 @@ static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym) update_stream(); - if (sindex_streams[pos->stream].id == -1) + if (semind_streams[pos->stream].id == -1) return; - if (!sindex_include_local_syms && sym_is_local(sym)) + if (!semind_include_local_syms && sym_is_local(sym)) return; if (!sym->ident) { @@ -720,7 +730,7 @@ static void r_symbol(unsigned mode, struct position *pos, struct symbol *sym) rec.sym_len = sym->ident->len; rec.kind = sym->kind; rec.mode = mode; - rec.file = sindex_streams[pos->stream].id; + rec.file = semind_streams[pos->stream].id; rec.line = pos->line; rec.col = pos->pos; @@ -737,10 +747,10 @@ static void r_member(unsigned mode, struct position *pos, struct symbol *sym, st update_stream(); - if (sindex_streams[pos->stream].id == -1) + if (semind_streams[pos->stream].id == -1) return; - if (!sindex_include_local_syms && sym_is_local(sym)) + if (!semind_include_local_syms && sym_is_local(sym)) return; ni = built_in_ident("?"); @@ -759,7 +769,7 @@ static void r_member(unsigned mode, struct position *pos, struct symbol *sym, st rec.sym_len = si->len + mi->len + 1; rec.kind = 'm'; rec.mode = mode; - rec.file = sindex_streams[pos->stream].id; + rec.file = semind_streams[pos->stream].id; rec.line = pos->line; rec.col = pos->pos; @@ -796,7 +806,7 @@ static void command_add(int argc, char **argv) &unlock_stmt); sqlite_prepare_persistent( - "INSERT OR IGNORE INTO tempdb.sindex " + "INSERT OR IGNORE INTO tempdb.semind " "(context, symbol, kind, mode, file, line, column) " "VALUES (@context, @symbol, @kind, @mode, @file, @line, @column)", &insert_rec_stmt); @@ -813,10 +823,10 @@ static void command_add(int argc, char **argv) "DELETE FROM file WHERE name == @name", &delete_file_stmt); - dissect(&reporter, sindex_filelist); + dissect(&reporter, semind_filelist); sqlite_run(lock_stmt); - sqlite_command("INSERT OR IGNORE INTO sindex SELECT * FROM tempdb.sindex"); + sqlite_command("INSERT OR IGNORE INTO semind SELECT * FROM tempdb.semind"); sqlite_run(unlock_stmt); sqlite3_finalize(insert_rec_stmt); @@ -825,7 +835,7 @@ static void command_add(int argc, char **argv) sqlite3_finalize(delete_file_stmt); sqlite3_finalize(lock_stmt); sqlite3_finalize(unlock_stmt); - free(sindex_streams); + free(semind_streams); } static void command_rm(int argc, char **argv) @@ -835,7 +845,7 @@ static void command_rm(int argc, char **argv) sqlite_command("BEGIN IMMEDIATE"); sqlite_prepare("DELETE FROM file WHERE name GLOB @file", &stmt); - if (sindex_verbose > 1) + if (semind_verbose > 1) message("SQL: %s", sqlite3_sql(stmt)); for (int i = 0; i < argc; i++) { @@ -867,12 +877,12 @@ static inline void print_mode(char *value) #undef U } -static char *sindex_file_name; -static FILE *sindex_file_fd; -static int sindex_file_lnum; -static char *sindex_line; -static size_t sindex_line_buflen; -static int sindex_line_len; +static char *semind_file_name; +static FILE *semind_file_fd; +static int semind_file_lnum; +static char *semind_line; +static size_t semind_line_buflen; +static int semind_line_len; static void print_file_line(const char *name, int lnum) { @@ -880,43 +890,43 @@ static void print_file_line(const char *name, int lnum) * All files are sorted by name and line number. So, we can reopen * the file and read it line by line. */ - if (!sindex_file_name || strcmp(sindex_file_name, name)) { - if (sindex_file_fd) { - fclose(sindex_file_fd); - free(sindex_file_name); + if (!semind_file_name || strcmp(semind_file_name, name)) { + if (semind_file_fd) { + fclose(semind_file_fd); + free(semind_file_name); } - sindex_file_name = strdup(name); + semind_file_name = strdup(name); - if (!sindex_file_name) - sindex_error(1, errno, "strdup"); + if (!semind_file_name) + semind_error(1, errno, "strdup"); - sindex_file_fd = fopen(name, "r"); + semind_file_fd = fopen(name, "r"); - if (!sindex_file_fd) - sindex_error(1, errno, "fopen: %s", name); + if (!semind_file_fd) + semind_error(1, errno, "fopen: %s", name); - sindex_file_lnum = 0; + semind_file_lnum = 0; } do { - if (sindex_file_lnum == lnum) { - if (sindex_line[sindex_line_len-1] == '\n') - sindex_line_len--; - printf("%.*s", sindex_line_len, sindex_line); + if (semind_file_lnum == lnum) { + if (semind_line[semind_line_len-1] == '\n') + semind_line_len--; + printf("%.*s", semind_line_len, semind_line); break; } - sindex_file_lnum++; + semind_file_lnum++; errno = 0; - } while((sindex_line_len = getline(&sindex_line, &sindex_line_buflen, sindex_file_fd)) != -1); + } while((semind_line_len = getline(&semind_line, &semind_line_buflen, semind_file_fd)) != -1); if (errno && errno != EOF) - sindex_error(1, errno, "getline"); + semind_error(1, errno, "getline"); } static int search_query_callback(void *data, int argc, char **argv, char **colname) { - char *fmt = (char *) sindex_search_format; + char *fmt = (char *) semind_search_format; char buf[32]; int quote = 0; int n = 0; @@ -938,7 +948,7 @@ static int search_query_callback(void *data, int argc, char **argv, char **colna c = *fmt; if (c == '\0') - sindex_error(1, 0, "unexpected end of format string"); + semind_error(1, 0, "unexpected end of format string"); switch (c) { case 'f': colnum = 0; goto print_string; @@ -985,7 +995,7 @@ static int search_query_callback(void *data, int argc, char **argv, char **colna } if (pos == fmt) - sindex_error(1, 0, "invalid format specification: %%%c", c); + semind_error(1, 0, "invalid format specification: %%%c", c); continue; } else if (c == '\\') { @@ -1014,101 +1024,104 @@ static void command_search(int argc, char **argv) { char *sql; char *dberr = NULL; - sqlite3_str *query = sqlite3_str_new(sindex_db); + sqlite3_str *query = sqlite3_str_new(semind_db); + + if (chdir(cwd) < 0) + semind_error(1, errno, "unable to change directory: %s", cwd); if (query_appendf(query, "SELECT" " file.name," - " sindex.line," - " sindex.column," - " sindex.context," - " sindex.symbol," - " sindex.mode," - " sindex.kind " - "FROM sindex, file " - "WHERE sindex.file == file.id") < 0) + " semind.line," + " semind.column," + " semind.context," + " semind.symbol," + " semind.mode," + " semind.kind " + "FROM semind, file " + "WHERE semind.file == file.id") < 0) goto fail; - if (sindex_search_kind) { - if (query_appendf(query, " AND sindex.kind == %d", sindex_search_kind) < 0) + if (semind_search_kind) { + if (query_appendf(query, " AND semind.kind == %d", semind_search_kind) < 0) goto fail; } - if (sindex_search_symbol) { + if (semind_search_symbol) { int ret; if (query_appendf(query, " AND ") < 0) goto fail; - if (strpbrk(sindex_search_symbol, "*?[]")) - ret = query_appendf(query, "sindex.symbol GLOB %Q", sindex_search_symbol); + if (strpbrk(semind_search_symbol, "*?[]")) + ret = query_appendf(query, "semind.symbol GLOB %Q", semind_search_symbol); else - ret = query_appendf(query, "sindex.symbol == %Q", sindex_search_symbol); + ret = query_appendf(query, "semind.symbol == %Q", semind_search_symbol); if (ret < 0) goto fail; } - if (sindex_search_modmask_defined) { - if (!sindex_search_modmask) { - if (query_appendf(query, " AND sindex.mode == %d", sindex_search_modmask) < 0) + if (semind_search_modmask_defined) { + if (!semind_search_modmask) { + if (query_appendf(query, " AND semind.mode == %d", semind_search_modmask) < 0) goto fail; - } else if (query_appendf(query, " AND (sindex.mode & %d) != 0", sindex_search_modmask) < 0) + } else if (query_appendf(query, " AND (semind.mode & %d) != 0", semind_search_modmask) < 0) goto fail; } - if (sindex_search_path) { - if (query_appendf(query, " AND file.name GLOB %Q", sindex_search_path) < 0) + if (semind_search_path) { + if (query_appendf(query, " AND file.name GLOB %Q", semind_search_path) < 0) goto fail; } - if (sindex_search_by_location == EXPLAIN_LOCATION) { - if (query_appendf(query, " AND file.name == %Q", sindex_search_filename) < 0) + if (semind_search_by_location == EXPLAIN_LOCATION) { + if (query_appendf(query, " AND file.name == %Q", semind_search_filename) < 0) goto fail; - if (sindex_search_line && - query_appendf(query, " AND sindex.line == %d", sindex_search_line) < 0) + if (semind_search_line && + query_appendf(query, " AND semind.line == %d", semind_search_line) < 0) goto fail; - if (sindex_search_column && - query_appendf(query, " AND sindex.column == %d", sindex_search_column) < 0) + if (semind_search_column && + query_appendf(query, " AND semind.column == %d", semind_search_column) < 0) goto fail; - } else if (sindex_search_by_location == USAGE_BY_LOCATION) { - if (query_appendf(query, " AND sindex.symbol IN (") < 0) + } else if (semind_search_by_location == USAGE_BY_LOCATION) { + if (query_appendf(query, " AND semind.symbol IN (") < 0) goto fail; if (query_appendf(query, - "SELECT sindex.symbol FROM sindex, file WHERE" - " sindex.file == file.id AND" - " file.name == %Q", sindex_search_filename) < 0) + "SELECT semind.symbol FROM semind, file WHERE" + " semind.file == file.id AND" + " file.name == %Q", semind_search_filename) < 0) goto fail; - if (sindex_search_line && - query_appendf(query, " AND sindex.line == %d", sindex_search_line) < 0) + if (semind_search_line && + query_appendf(query, " AND semind.line == %d", semind_search_line) < 0) goto fail; - if (sindex_search_column && - query_appendf(query, " AND sindex.column == %d", sindex_search_column) < 0) + if (semind_search_column && + query_appendf(query, " AND semind.column == %d", semind_search_column) < 0) goto fail; if (query_appendf(query, ")") < 0) goto fail; } - if (query_appendf(query, " ORDER BY file.name, sindex.line, sindex.column ASC", sindex_search_path) < 0) + if (query_appendf(query, " ORDER BY file.name, semind.line, semind.column ASC", semind_search_path) < 0) goto fail; sql = sqlite3_str_value(query); - if (sindex_verbose > 1) + if (semind_verbose > 1) message("SQL: %s", sql); - sqlite3_exec(sindex_db, sql, search_query_callback, NULL, &dberr); + sqlite3_exec(semind_db, sql, search_query_callback, NULL, &dberr); if (dberr) - sindex_error(1, 0, "sql query failed: %s", dberr); + semind_error(1, 0, "sql query failed: %s", dberr); fail: sql = sqlite3_str_finish(query); sqlite3_free(sql); - if (sindex_file_fd) { - fclose(sindex_file_fd); - free(sindex_file_name); + if (semind_file_fd) { + fclose(semind_file_fd); + free(semind_file_name); } - free(sindex_line); + free(semind_line); } @@ -1143,25 +1156,25 @@ int main(int argc, char **argv) progname++; if (!realpath(".", cwd)) - sindex_error(1, errno, "unable to get current directory"); + semind_error(1, errno, "unable to get current directory"); n_cwd = strlen(cwd); parse_cmdline(argc, argv); for (cmd = commands; cmd->name && strcmp(argv[optind], cmd->name); cmd++); if (!cmd->name) - sindex_error(1, 0, "unknown command: %s", argv[optind]); + semind_error(1, 0, "unknown command: %s", argv[optind]); optind++; - sindex_command = cmd->name; + semind_command = cmd->name; if (cmd->parse_cmdline) cmd->parse_cmdline(argc, argv); - open_database(sindex_dbfile, cmd->dbflags); + open_database(semind_dbfile, cmd->dbflags); cmd->handler(argc - optind, argv + optind); - sqlite3_close(sindex_db); + sqlite3_close(semind_db); return 0; } @@ -754,28 +754,18 @@ static long long check_shift_count(struct instruction *insn, unsigned long long unsigned int size = insn->size; long long sval = uval; + if (insn->tainted) + return -1; + if (uval < size) return uval; + insn->tainted = 1; sval = sign_extend_safe(sval, size); sval = sign_extend_safe(sval, bits_in_int); if (sval < 0) insn->src2 = value_pseudo(sval); - if (insn->tainted) - return sval; - - if (sval < 0 && Wshift_count_negative) - warning(insn->pos, "shift count is negative (%lld)", sval); - if (sval > 0 && Wshift_count_overflow) { - struct symbol *ctype = insn->type; - const char *tname; - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - tname = show_typename(ctype); - warning(insn->pos, "shift too big (%llu) for type %s", sval, tname); - } - insn->tainted = 1; - return sval; + return -1; } static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value) @@ -513,7 +513,7 @@ By default chars are signed. .BR cgcc (1) . .SH HOMEPAGE -http://www.kernel.org/pub/software/devel/sparse/ +https://sparse.docs.kernel.org . .SH MAILING LIST linux-sparse@vger.kernel.org @@ -307,6 +307,29 @@ void merge_type(struct symbol *sym, struct symbol *base_type) merge_type(sym, sym->ctype.base_type); } +static bool is_wstring_expr(struct expression *expr) +{ + while (expr) { + switch (expr->type) { + case EXPR_STRING: + return 1; + case EXPR_INITIALIZER: + if (expression_list_size(expr->expr_list) != 1) + return 0; + expr = first_expression(expr->expr_list); + break; + case EXPR_PREOP: + if (expr->op == '(') { + expr = expr->unop; + break; + } + default: + return 0; + } + } + return 0; +} + static int count_array_initializer(struct symbol *t, struct expression *expr) { int nr = 0; @@ -321,6 +344,8 @@ static int count_array_initializer(struct symbol *t, struct expression *expr) */ if (t->ctype.base_type == &int_type && t->rank == -2) is_char = 1; + else if (t == wchar_ctype && is_wstring_expr(expr)) + is_char = 1; switch (expr->type) { case EXPR_INITIALIZER: { @@ -776,7 +801,7 @@ struct symbol zero_int; void init_symbols(void) { - int stream = init_stream("builtin", -1, includepath, -1); + int stream = init_stream(NULL, "builtin", -1, includepath); #define __IDENT(n,str,res) \ hash_ident(&n) @@ -81,7 +81,7 @@ enum keyword { KW_BUILTIN = 1 << 4, KW_ASM = 1 << 5, KW_MODE = 1 << 6, - // KW UNUSED = 1 << 7, + KW_STATIC = 1 << 7, // KW UNUSED = 1 << 8, KW_EXACT = 1 << 9, }; @@ -206,9 +206,10 @@ struct symbol { union /* backend */ { struct basic_block *bb_target; /* label */ void *aux; /* Auxiliary info, e.g. backend information */ - struct { /* sparse ctags */ - char kind; + struct { + char kind; /* used by ctags & dissect */ unsigned char visited:1; + unsigned char inspected:1; }; }; pseudo_t pseudo; @@ -429,6 +430,13 @@ static inline int is_byte_type(struct symbol *type) return type->bit_size == bits_in_char && type->type != SYM_BITFIELD; } +static inline int is_wchar_type(struct symbol *type) +{ + if (type->type == SYM_NODE) + type = type->ctype.base_type; + return type == wchar_ctype; +} + static inline int is_void_type(struct symbol *type) { if (type->type == SYM_NODE) diff --git a/target-xtensa.c b/target-xtensa.c index 26bda47f..3620b4a3 100644 --- a/target-xtensa.c +++ b/target-xtensa.c @@ -17,11 +17,6 @@ static void predefine_xtensa(const struct target *self) { predefine("__XTENSA__", 1, "1"); predefine("__xtensa__", 1, "1"); - - if (arch_big_endian) - predefine("__XTENSA_EB__", 1, "1"); - else - predefine("__XTENSA_EL__", 1, "1"); } const struct target target_xtensa = { @@ -49,10 +49,11 @@ enum constantfile { extern const char *includepath[]; struct stream { - int fd, prev; + int fd; const char *name; const char *path; // input-file path - see set_stream_include_path() const char **next_path; + struct position pos; //position of the #include, if any /* Use these to check for "already parsed" */ enum constantfile constant; @@ -214,7 +215,7 @@ static inline struct token *containing_token(struct token **p) extern struct token eof_token_entry; #define eof_token(x) ((x) == &eof_token_entry) -extern int init_stream(const char *, int fd, const char **next_path, int prev_stream); +extern int init_stream(const struct position *pos, const char *, int fd, const char **next_path); extern int stream_prev(int stream); extern const char *stream_name(int stream); extern struct ident *hash_ident(struct ident *); @@ -225,7 +226,7 @@ extern const char *show_ident(const struct ident *); extern const char *show_string(const struct string *string); extern const char *show_token(const struct token *); extern const char *quote_token(const struct token *); -extern struct token * tokenize(const char *, int, int, struct token *, const char **next_path); +extern struct token * tokenize(const struct position *pos, const char *, int, struct token *, const char **next_path); extern struct token * tokenize_buffer(void *, unsigned long, struct token **); extern void show_identifier_stats(void); @@ -66,7 +66,10 @@ int stream_prev(int stream) { if (stream < 0 || stream > input_stream_nr) return -1; - return input_streams[stream].prev; + stream = input_streams[stream].pos.stream; + if (stream > input_stream_nr) + return -1; + return stream; } static struct position stream_pos(stream_t *stream) @@ -307,7 +310,7 @@ int *hash_stream(const char *name) return input_stream_hashes + hash; } -int init_stream(const char *name, int fd, const char **next_path, int prev_stream) +int init_stream(const struct position *pos, const char *name, int fd, const char **next_path) { int stream = input_stream_nr, *hash; struct stream *current; @@ -326,7 +329,10 @@ int init_stream(const char *name, int fd, const char **next_path, int prev_strea current->next_path = next_path; current->path = NULL; current->constant = CONSTANT_FILE_MAYBE; - current->prev = prev_stream; + if (pos) + current->pos = *pos; + else + current->pos.stream = -1; input_stream_nr = stream+1; hash = hash_stream(name); current->next_stream = *hash; @@ -1009,14 +1015,14 @@ struct token * tokenize_buffer(void *buffer, unsigned long size, struct token ** return begin; } -struct token * tokenize(const char *name, int fd, int prev_stream, struct token *endtoken, const char **next_path) +struct token * tokenize(const struct position *pos, const char *name, int fd, struct token *endtoken, const char **next_path) { struct token *begin, *end; stream_t stream; unsigned char buffer[BUFSIZE]; int idx; - idx = init_stream(name, fd, next_path, prev_stream); + idx = init_stream(pos, name, fd, next_path); if (idx < 0) { // info(endtoken->pos, "File %s is const", name); return endtoken; diff --git a/validation/abstract-array-declarator-quals.c b/validation/abstract-array-declarator-quals.c new file mode 100644 index 00000000..e69df902 --- /dev/null +++ b/validation/abstract-array-declarator-quals.c @@ -0,0 +1,21 @@ +#define N 2 + +void ok1(int []); +void ok2(int [N]); +void ok3(int [const volatile restrict]); +void ok4(int [const volatile restrict N]); +void ok5(int [static N]); +void ok6(int [static const volatile restrict N]); +void ok7(int [const volatile restrict static N]); + +void ok1(int a[]); +void ok2(int a[N]); +void ok3(int a[const volatile restrict]); +void ok4(int a[const volatile restrict N]); +void ok5(int a[static N]); +void ok6(int a[static const volatile restrict N]); +void ok7(int a[const volatile restrict static N]); + +/* + * check-name: abstract-array-declarator-quals + */ diff --git a/validation/abstract-array-declarator-star.c b/validation/abstract-array-declarator-star.c new file mode 100644 index 00000000..fc42da3a --- /dev/null +++ b/validation/abstract-array-declarator-star.c @@ -0,0 +1,8 @@ +void ok8(int [*]); + +void ok8(int a[*]); +void ok9(int a[const volatile restrict *]); + +/* + * check-name: abstract-array-declarator-star + */ diff --git a/validation/abstract-array-declarator.c b/validation/abstract-array-declarator.c new file mode 100644 index 00000000..ca182373 --- /dev/null +++ b/validation/abstract-array-declarator.c @@ -0,0 +1,11 @@ +void f77(int a[1, 2]); +void c99(int a[(1, 2)]); + +/* + * check-name: abstract-array-declarator + * + * check-error-start +abstract-array-declarator.c:1:17: error: Expected ] in abstract_array_declarator +abstract-array-declarator.c:1:17: error: got , + * check-error-end + */ diff --git a/validation/builtin-sync-cas.c b/validation/builtin-sync-cas.c new file mode 100644 index 00000000..846e21bb --- /dev/null +++ b/validation/builtin-sync-cas.c @@ -0,0 +1,25 @@ +static int *foo(int *ptr) +{ + __sync_val_compare_and_swap(ptr, 123, 0L); + return __sync_val_compare_and_swap(&ptr, ptr, ptr); +} + +static long bar(long *ptr) +{ + return __sync_val_compare_and_swap(ptr, ptr, 1); +} + +static _Bool boz(_Bool *ptr) +{ + return __sync_bool_compare_and_swap(ptr, 0, ptr); +} + +/* + * check-name: builtin-sync-cas + * + * check-error-start +builtin-sync-cas.c:9:49: warning: incorrect type in argument 2 (different base types) +builtin-sync-cas.c:9:49: expected long +builtin-sync-cas.c:9:49: got long *ptr + * check-error-end + */ diff --git a/validation/expand/bad-shift.c b/validation/expand/bad-shift.c index 22c4341f..b68866c2 100644 --- a/validation/expand/bad-shift.c +++ b/validation/expand/bad-shift.c @@ -56,9 +56,9 @@ rneg: * check-output-end * * check-error-start -expand/bad-shift.c:5:18: warning: shift too big (32) for type int -expand/bad-shift.c:10:18: warning: shift count is negative (-1) -expand/bad-shift.c:15:18: warning: shift too big (32) for type int -expand/bad-shift.c:20:18: warning: shift count is negative (-1) +expand/bad-shift.c:5:21: warning: shift too big (32) for type int +expand/bad-shift.c:10:21: warning: shift count is negative (-1) +expand/bad-shift.c:15:21: warning: shift too big (32) for type int +expand/bad-shift.c:20:21: warning: shift count is negative (-1) * check-error-end */ diff --git a/validation/init-wstring.c b/validation/init-wstring.c new file mode 100644 index 00000000..d9ce3b3c --- /dev/null +++ b/validation/init-wstring.c @@ -0,0 +1,40 @@ +static const __WCHAR_TYPE__ ok0[] = L"abc"; +_Static_assert(sizeof(ok0) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok1[] = (L"abc"); +_Static_assert(sizeof(ok1) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok2[] = { L"abc" }; +_Static_assert(sizeof(ok2) == 4 * sizeof(__WCHAR_TYPE__)); + +static const __WCHAR_TYPE__ ok3[4] = L"abc"; +_Static_assert(sizeof(ok3) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok4[4] = (L"abc"); +_Static_assert(sizeof(ok4) == 4 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok5[4] = { (L"abc") }; +_Static_assert(sizeof(ok5) == 4 * sizeof(__WCHAR_TYPE__)); + +static const __WCHAR_TYPE__ ok6[7] = L"abc"; +_Static_assert(sizeof(ok6) == 7 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok7[7] = (L"abc"); +_Static_assert(sizeof(ok7) == 7 * sizeof(__WCHAR_TYPE__)); +static const __WCHAR_TYPE__ ok8[7] = { (L"abc") }; +_Static_assert(sizeof(ok8) == 7 * sizeof(__WCHAR_TYPE__)); + +static const __WCHAR_TYPE__ *ptr[] = { L"abc" }; +_Static_assert(sizeof(ptr) == sizeof(void *)); + +static struct s { + const __WCHAR_TYPE__ str[4]; +} str = { L"xyz" }; + +static const __WCHAR_TYPE__ ko3[3] = L"abc"; +static const __WCHAR_TYPE__ ko2[2] = L"abc"; + +/* + * check-name: init-wstring + * check-command: sparse -Winit-cstring $file + * + * check-error-start +init-wstring.c:29:38: warning: too long initializer-string for array of char(no space for nul char) +init-wstring.c:30:38: warning: too long initializer-string for array of char + * check-error-end + */ diff --git a/validation/init_cstring.c b/validation/init_cstring.c index 00eca20a..bac814e4 100644 --- a/validation/init_cstring.c +++ b/validation/init_cstring.c @@ -1,11 +1,13 @@ static struct alpha { char a[2]; } x = { .a = "ab" }; +static const char str[2] = "abc"; /* * check-name: -Winit-cstring option * * check-command: sparse -Winit-cstring $file * check-error-start init_cstring.c:3:14: warning: too long initializer-string for array of char(no space for nul char) +init_cstring.c:4:28: warning: too long initializer-string for array of char * check-error-end */ diff --git a/validation/inline-generic.c b/validation/inline-generic.c new file mode 100644 index 00000000..1f05c079 --- /dev/null +++ b/validation/inline-generic.c @@ -0,0 +1,10 @@ +extern int a, b; +inline int c(void) { return a++; } +inline int e(int d) { return 0; } +inline unsigned f(void) { return e(_Generic(b, int: c())); } +static int g(void) { return f(); } +static int h(void) { return f(); } + +/* + * check-name: inline-generic + */ diff --git a/validation/linear/bug-assign-op0.c b/validation/linear/bug-assign-op0.c index 0cabc622..b351bb51 100644 --- a/validation/linear/bug-assign-op0.c +++ b/validation/linear/bug-assign-op0.c @@ -46,7 +46,6 @@ unsigned int sldivu(unsigned int u, long s) /* * check-name: bug-assign-op0 * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-start asr: diff --git a/validation/linear/shift-assign1.c b/validation/linear/shift-assign1.c new file mode 100644 index 00000000..4c96fc28 --- /dev/null +++ b/validation/linear/shift-assign1.c @@ -0,0 +1,319 @@ +typedef __INT16_TYPE__ s16; +typedef __INT32_TYPE__ s32; +typedef __INT64_TYPE__ s64; +typedef __UINT16_TYPE__ u16; +typedef __UINT32_TYPE__ u32; +typedef __UINT64_TYPE__ u64; + +s16 s16s16(s16 a, s16 b) { a >>= b; return a; } +s16 s16s32(s16 a, s32 b) { a >>= b; return a; } +s16 s16s64(s16 a, s64 b) { a >>= b; return a; } +s16 s16u16(s16 a, u16 b) { a >>= b; return a; } +s16 s16u32(s16 a, u32 b) { a >>= b; return a; } +s16 s16u64(s16 a, u64 b) { a >>= b; return a; } +s32 s32s16(s32 a, s16 b) { a >>= b; return a; } +s32 s32s32(s32 a, s32 b) { a >>= b; return a; } +s32 s32s64(s32 a, s64 b) { a >>= b; return a; } +s32 s32u16(s32 a, u16 b) { a >>= b; return a; } +s32 s32u32(s32 a, u32 b) { a >>= b; return a; } +s32 s32u64(s32 a, u64 b) { a >>= b; return a; } +s64 s64s16(s64 a, s16 b); +s64 s64s32(s64 a, s32 b); +s64 s64s64(s64 a, s64 b) { a >>= b; return a; } +s64 s64u16(s64 a, u16 b) { a >>= b; return a; } +s64 s64u32(s64 a, u32 b) { a >>= b; return a; } +s64 s64u64(s64 a, u64 b) { a >>= b; return a; } +u16 u16s16(u16 a, s16 b) { a >>= b; return a; } +u16 u16s32(u16 a, s32 b) { a >>= b; return a; } +u16 u16s64(u16 a, s64 b) { a >>= b; return a; } +u16 u16u16(u16 a, u16 b) { a >>= b; return a; } +u16 u16u32(u16 a, u32 b) { a >>= b; return a; } +u16 u16u64(u16 a, u64 b) { a >>= b; return a; } +u32 u32s16(u32 a, s16 b) { a >>= b; return a; } +u32 u32s32(u32 a, s32 b) { a >>= b; return a; } +u32 u32s64(u32 a, s64 b) { a >>= b; return a; } +u32 u32u16(u32 a, u16 b) { a >>= b; return a; } +u32 u32u32(u32 a, u32 b) { a >>= b; return a; } +u32 u32u64(u32 a, u64 b) { a >>= b; return a; } +u64 u64s16(u64 a, s16 b); +u64 u64s32(u64 a, s32 b); +u64 u64s64(u64 a, s64 b) { a >>= b; return a; } +u64 u64u16(u64 a, u16 b) { a >>= b; return a; } +u64 u64u32(u64 a, u32 b) { a >>= b; return a; } +u64 u64u64(u64 a, u64 b) { a >>= b; return a; } + +/* + * check-name: shift-assign1 + * check-command: test-linearize -Wno-decl $file + * + * check-output-start +s16s16: +.L0: + <entry-point> + sext.32 %r2 <- (16) %arg2 + sext.32 %r4 <- (16) %arg1 + asr.32 %r5 <- %r4, %r2 + trunc.16 %r6 <- (32) %r5 + ret.16 %r6 + + +s16s32: +.L2: + <entry-point> + sext.32 %r11 <- (16) %arg1 + asr.32 %r12 <- %r11, %arg2 + trunc.16 %r13 <- (32) %r12 + ret.16 %r13 + + +s16s64: +.L4: + <entry-point> + trunc.32 %r17 <- (64) %arg2 + sext.32 %r19 <- (16) %arg1 + asr.32 %r20 <- %r19, %r17 + trunc.16 %r21 <- (32) %r20 + ret.16 %r21 + + +s16u16: +.L6: + <entry-point> + zext.32 %r25 <- (16) %arg2 + sext.32 %r27 <- (16) %arg1 + asr.32 %r28 <- %r27, %r25 + trunc.16 %r29 <- (32) %r28 + ret.16 %r29 + + +s16u32: +.L8: + <entry-point> + sext.32 %r34 <- (16) %arg1 + asr.32 %r35 <- %r34, %arg2 + trunc.16 %r36 <- (32) %r35 + ret.16 %r36 + + +s16u64: +.L10: + <entry-point> + trunc.32 %r40 <- (64) %arg2 + sext.32 %r42 <- (16) %arg1 + asr.32 %r43 <- %r42, %r40 + trunc.16 %r44 <- (32) %r43 + ret.16 %r44 + + +s32s16: +.L12: + <entry-point> + sext.32 %r48 <- (16) %arg2 + asr.32 %r50 <- %arg1, %r48 + ret.32 %r50 + + +s32s32: +.L14: + <entry-point> + asr.32 %r55 <- %arg1, %arg2 + ret.32 %r55 + + +s32s64: +.L16: + <entry-point> + trunc.32 %r59 <- (64) %arg2 + asr.32 %r61 <- %arg1, %r59 + ret.32 %r61 + + +s32u16: +.L18: + <entry-point> + zext.32 %r65 <- (16) %arg2 + asr.32 %r67 <- %arg1, %r65 + ret.32 %r67 + + +s32u32: +.L20: + <entry-point> + asr.32 %r72 <- %arg1, %arg2 + ret.32 %r72 + + +s32u64: +.L22: + <entry-point> + trunc.32 %r76 <- (64) %arg2 + asr.32 %r78 <- %arg1, %r76 + ret.32 %r78 + + +s64s64: +.L24: + <entry-point> + asr.64 %r83 <- %arg1, %arg2 + ret.64 %r83 + + +s64u16: +.L26: + <entry-point> + zext.64 %r88 <- (16) %arg2 + asr.64 %r90 <- %arg1, %r88 + ret.64 %r90 + + +s64u32: +.L28: + <entry-point> + zext.64 %r94 <- (32) %arg2 + asr.64 %r96 <- %arg1, %r94 + ret.64 %r96 + + +s64u64: +.L30: + <entry-point> + asr.64 %r101 <- %arg1, %arg2 + ret.64 %r101 + + +u16s16: +.L32: + <entry-point> + sext.32 %r105 <- (16) %arg2 + zext.32 %r107 <- (16) %arg1 + asr.32 %r108 <- %r107, %r105 + trunc.16 %r109 <- (32) %r108 + ret.16 %r109 + + +u16s32: +.L34: + <entry-point> + zext.32 %r114 <- (16) %arg1 + asr.32 %r115 <- %r114, %arg2 + trunc.16 %r116 <- (32) %r115 + ret.16 %r116 + + +u16s64: +.L36: + <entry-point> + trunc.32 %r120 <- (64) %arg2 + zext.32 %r122 <- (16) %arg1 + asr.32 %r123 <- %r122, %r120 + trunc.16 %r124 <- (32) %r123 + ret.16 %r124 + + +u16u16: +.L38: + <entry-point> + zext.32 %r128 <- (16) %arg2 + zext.32 %r130 <- (16) %arg1 + asr.32 %r131 <- %r130, %r128 + trunc.16 %r132 <- (32) %r131 + ret.16 %r132 + + +u16u32: +.L40: + <entry-point> + zext.32 %r137 <- (16) %arg1 + asr.32 %r138 <- %r137, %arg2 + trunc.16 %r139 <- (32) %r138 + ret.16 %r139 + + +u16u64: +.L42: + <entry-point> + trunc.32 %r143 <- (64) %arg2 + zext.32 %r145 <- (16) %arg1 + asr.32 %r146 <- %r145, %r143 + trunc.16 %r147 <- (32) %r146 + ret.16 %r147 + + +u32s16: +.L44: + <entry-point> + sext.32 %r151 <- (16) %arg2 + lsr.32 %r153 <- %arg1, %r151 + ret.32 %r153 + + +u32s32: +.L46: + <entry-point> + lsr.32 %r158 <- %arg1, %arg2 + ret.32 %r158 + + +u32s64: +.L48: + <entry-point> + trunc.32 %r162 <- (64) %arg2 + lsr.32 %r164 <- %arg1, %r162 + ret.32 %r164 + + +u32u16: +.L50: + <entry-point> + zext.32 %r168 <- (16) %arg2 + lsr.32 %r170 <- %arg1, %r168 + ret.32 %r170 + + +u32u32: +.L52: + <entry-point> + lsr.32 %r175 <- %arg1, %arg2 + ret.32 %r175 + + +u32u64: +.L54: + <entry-point> + trunc.32 %r179 <- (64) %arg2 + lsr.32 %r181 <- %arg1, %r179 + ret.32 %r181 + + +u64s64: +.L56: + <entry-point> + lsr.64 %r186 <- %arg1, %arg2 + ret.64 %r186 + + +u64u16: +.L58: + <entry-point> + zext.64 %r191 <- (16) %arg2 + lsr.64 %r193 <- %arg1, %r191 + ret.64 %r193 + + +u64u32: +.L60: + <entry-point> + zext.64 %r197 <- (32) %arg2 + lsr.64 %r199 <- %arg1, %r197 + ret.64 %r199 + + +u64u64: +.L62: + <entry-point> + lsr.64 %r204 <- %arg1, %arg2 + ret.64 %r204 + + + * check-output-end + */ diff --git a/validation/linear/shift-assign2.c b/validation/linear/shift-assign2.c new file mode 100644 index 00000000..9990ac38 --- /dev/null +++ b/validation/linear/shift-assign2.c @@ -0,0 +1,53 @@ +typedef __INT16_TYPE__ s16; +typedef __INT32_TYPE__ s32; +typedef __INT64_TYPE__ s64; +typedef __UINT16_TYPE__ u16; +typedef __UINT32_TYPE__ u32; +typedef __UINT64_TYPE__ u64; + +s64 s64s16(s64 a, s16 b) { a >>= b; return a; } +s64 s64s32(s64 a, s32 b) { a >>= b; return a; } +u64 u64s16(u64 a, s16 b) { a >>= b; return a; } +u64 u64s32(u64 a, s32 b) { a >>= b; return a; } + +/* + * check-name: shift-assign2 + * check-command: test-linearize -Wno-decl $file + * + * check-output-start +s64s16: +.L0: + <entry-point> + sext.32 %r2 <- (16) %arg2 + zext.64 %r3 <- (32) %r2 + asr.64 %r5 <- %arg1, %r3 + ret.64 %r5 + + +s64s32: +.L2: + <entry-point> + zext.64 %r9 <- (32) %arg2 + asr.64 %r11 <- %arg1, %r9 + ret.64 %r11 + + +u64s16: +.L4: + <entry-point> + sext.32 %r15 <- (16) %arg2 + zext.64 %r16 <- (32) %r15 + lsr.64 %r18 <- %arg1, %r16 + ret.64 %r18 + + +u64s32: +.L6: + <entry-point> + zext.64 %r22 <- (32) %arg2 + lsr.64 %r24 <- %arg1, %r22 + ret.64 %r24 + + + * check-output-end + */ diff --git a/validation/optim/shift-big.c b/validation/optim/shift-big.c index 84bcd2ce..e7bf22fe 100644 --- a/validation/optim/shift-big.c +++ b/validation/optim/shift-big.c @@ -50,13 +50,15 @@ lsr31: lsr32: .L8: <entry-point> - ret.32 $0 + lsr.32 %r14 <- %arg1, $32 + ret.32 %r14 lsr33: .L10: <entry-point> - ret.32 $0 + lsr.32 %r17 <- %arg1, $33 + ret.32 %r17 shl31: @@ -69,13 +71,15 @@ shl31: shl32: .L14: <entry-point> - ret.32 $0 + shl.32 %r23 <- %arg1, $32 + ret.32 %r23 shl33: .L16: <entry-point> - ret.32 $0 + shl.32 %r26 <- %arg1, $33 + ret.32 %r26 * check-output-end diff --git a/validation/preprocessor/bad-cmdline-include.c b/validation/preprocessor/bad-cmdline-include.c new file mode 100644 index 00000000..e4ee03f4 --- /dev/null +++ b/validation/preprocessor/bad-cmdline-include.c @@ -0,0 +1,11 @@ +#error some random error + +/* + * check-name: bad-cmdline-include + * check-command: sparse -include $file + * + * check-error-start +command-line: note: in included file (through builtin): +preprocessor/bad-cmdline-include.c:1:2: error: some random error + * check-error-end + */ diff --git a/validation/shift-negative.c b/validation/shift-negative.c index fff5cf12..6df02b18 100644 --- a/validation/shift-negative.c +++ b/validation/shift-negative.c @@ -9,8 +9,8 @@ unsigned int fo2(unsigned int a) { return a >> ((a & 0) ^ ~0); } * check-command: sparse -Wno-decl $file * * check-error-start -shift-negative.c:1:45: warning: shift count is negative (-1) -shift-negative.c:2:45: warning: shift count is negative (-1) +shift-negative.c:1:48: warning: shift count is negative (-1) +shift-negative.c:2:48: warning: shift count is negative (-1) shift-negative.c:4:59: warning: shift count is negative (-1) shift-negative.c:5:59: warning: shift count is negative (-1) * check-error-end diff --git a/validation/shift-undef-long.c b/validation/shift-undef-long.c index 32626743..985fe4c4 100644 --- a/validation/shift-undef-long.c +++ b/validation/shift-undef-long.c @@ -13,9 +13,8 @@ static unsigned very_big_shift(unsigned int a) * check-command: sparse -m64 $file * * check-error-start -shift-undef-long.c:4:16: warning: shift too big (4294967295) for type unsigned int -shift-undef-long.c:5:16: warning: shift too big (4294967296) for type unsigned int -shift-undef-long.c:6:16: warning: shift too big (4294967296) for type unsigned int -shift-undef-long.c:7:16: warning: shift count is negative (-4294967296) +shift-undef-long.c:4:25: warning: shift count is negative (-1) +shift-undef-long.c:5:47: warning: shift too big (4294967296) for type unsigned int +shift-undef-long.c:7:20: warning: shift count is negative (-4294967296) * check-error-end */ diff --git a/validation/shift-undef.c b/validation/shift-undef.c index 4e94fa23..0c7541e9 100644 --- a/validation/shift-undef.c +++ b/validation/shift-undef.c @@ -112,51 +112,27 @@ void hw_write(u32 val) * check-command: sparse -Wno-decl $file * * check-error-start -shift-undef.c:3:15: warning: shift too big (100) for type int -shift-undef.c:4:15: warning: shift too big (101) for type unsigned int -shift-undef.c:5:15: warning: shift too big (102) for type unsigned int -shift-undef.c:6:15: warning: shift count is negative (-1) -shift-undef.c:7:15: warning: shift count is negative (-2) -shift-undef.c:8:15: warning: shift count is negative (-3) -shift-undef.c:9:25: warning: shift too big (103) for type int -shift-undef.c:10:25: warning: shift too big (104) for type unsigned int -shift-undef.c:11:25: warning: shift too big (105) for type unsigned int -shift-undef.c:12:25: warning: shift count is negative (-4) -shift-undef.c:13:25: warning: shift count is negative (-5) -shift-undef.c:14:25: warning: shift count is negative (-6) -shift-undef.c:15:30: warning: shift too big (106) for type int -shift-undef.c:16:30: warning: shift too big (107) for type unsigned int -shift-undef.c:17:30: warning: shift too big (108) for type unsigned int -shift-undef.c:18:30: warning: shift count is negative (-7) -shift-undef.c:19:30: warning: shift count is negative (-8) -shift-undef.c:20:30: warning: shift count is negative (-9) +shift-undef.c:3:18: warning: shift too big (100) for type int +shift-undef.c:4:18: warning: shift too big (101) for type unsigned int +shift-undef.c:5:18: warning: shift too big (102) for type unsigned int +shift-undef.c:6:19: warning: shift count is negative (-1) +shift-undef.c:7:19: warning: shift count is negative (-2) +shift-undef.c:8:19: warning: shift count is negative (-3) shift-undef.c:21:29: warning: shift too big (109) for type int shift-undef.c:22:29: warning: shift too big (110) for type unsigned int shift-undef.c:23:29: warning: shift too big (111) for type unsigned int shift-undef.c:24:29: warning: shift count is negative (-10) shift-undef.c:25:29: warning: shift count is negative (-11) shift-undef.c:26:29: warning: shift count is negative (-12) -shift-undef.c:32:11: warning: shift too big (100) for type int -shift-undef.c:33:11: warning: shift too big (101) for type unsigned int -shift-undef.c:34:11: warning: shift too big (102) for type unsigned int -shift-undef.c:35:11: warning: shift count is negative (-1) -shift-undef.c:36:11: warning: shift count is negative (-2) -shift-undef.c:37:11: warning: shift count is negative (-3) -shift-undef.c:38:25: warning: shift too big (103) for type int -shift-undef.c:39:25: warning: shift too big (104) for type unsigned int -shift-undef.c:40:25: warning: shift too big (105) for type unsigned int -shift-undef.c:41:25: warning: shift count is negative (-4) -shift-undef.c:42:25: warning: shift count is negative (-5) -shift-undef.c:43:25: warning: shift count is negative (-6) -shift-undef.c:44:30: warning: shift too big (106) for type int -shift-undef.c:45:30: warning: shift too big (107) for type unsigned int -shift-undef.c:46:30: warning: shift too big (108) for type unsigned int -shift-undef.c:47:30: warning: shift count is negative (-7) -shift-undef.c:48:30: warning: shift count is negative (-8) -shift-undef.c:49:30: warning: shift count is negative (-9) +shift-undef.c:32:15: warning: shift too big (100) for type int +shift-undef.c:33:15: warning: shift too big (101) for type unsigned int +shift-undef.c:34:15: warning: shift too big (102) for type unsigned int +shift-undef.c:35:16: warning: shift count is negative (-1) +shift-undef.c:36:16: warning: shift count is negative (-2) +shift-undef.c:37:16: warning: shift count is negative (-3) shift-undef.c:50:26: warning: shift too big (109) for type int -shift-undef.c:51:26: warning: shift too big (110) for type int -shift-undef.c:52:26: warning: shift too big (111) for type int +shift-undef.c:51:26: warning: shift too big (110) for type unsigned int +shift-undef.c:52:26: warning: shift too big (111) for type unsigned int shift-undef.c:53:26: warning: shift count is negative (-10) shift-undef.c:54:26: warning: shift count is negative (-11) shift-undef.c:55:26: warning: shift count is negative (-12) |