aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-02-08 12:49:03 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-02-08 12:49:03 +0100
commita695e053a24db2f092b76c7394ca57899b43e345 (patch)
treedd6da172ad272610f6569ca03061c1195ddd0b0a
parent6b91f6997c7debd4eaa03b8f9e222aaafa937498 (diff)
parent047a43fa754c0f82666d5858168bd63fe87d90a7 (diff)
downloadsparse-dev-a695e053a24db2f092b76c7394ca57899b43e345.tar.gz
Merge branches 'cse-setfval' and 'extract-eval' into tip
-rw-r--r--Documentation/data-structures.txt107
-rw-r--r--Documentation/test-suite8
-rw-r--r--evaluate.c70
-rw-r--r--lib.c1
-rw-r--r--linearize.c4
-rw-r--r--simplify.c241
-rw-r--r--sparse.17
-rw-r--r--symbol.c4
-rw-r--r--symbol.h5
-rw-r--r--validation/bad-type-twice0.c13
-rw-r--r--validation/bad-type-twice1.c16
-rw-r--r--validation/bad-type-twice2.c18
-rw-r--r--validation/ptr-sub-blows.c23
-rw-r--r--validation/typeof-bad.c17
14 files changed, 331 insertions, 203 deletions
diff --git a/Documentation/data-structures.txt b/Documentation/data-structures.txt
index 3745b54c..14419263 100644
--- a/Documentation/data-structures.txt
+++ b/Documentation/data-structures.txt
@@ -1,54 +1,55 @@
+- A slightly edited irc discussion with Josh Triplett.
+- Describes most data structures used in sparse.
-<JoshTriplett> As far as the parsing structures go...
-<JoshTriplett> The C parser exists in two main files: parse.c, which parses statements, and expression.c, which parses expressions.
-<JoshTriplett> parse.h contains the definition of struct statement, which represents a C statement.
-<JoshTriplett> That includes only those things which can't appear as an expression, which primarily includes control flow statements such as if, loops, switch/case, and goto.
-<JoshTriplett> expression.h contains the definition of struct expression, which represents a C expression. That has a lot more content, since most C constructs can appear in expressions.
-<JoshTriplett> A series of statements forms a compound statement (STMT_COMPOUND).
-<JoshTriplett> That appears as another struct statement which has a statement_list member.
-<JoshTriplett> A function body consists of a compound statement.
-<JoshTriplett> When you look at a loop body, if or else body, or case body, you'll notice that they just have a struct statement, not a statement_list; they can have multiple statements by using a compound statement.
-<JoshTriplett> Also note that all loops get turned into a single "iterator" statement.
-<JoshTriplett> for, while, and do-while.
-<JoshTriplett> A symbol, then, represents a name in a C file. A symbol might represent a variable, a function, a label, or various other things.
-<JoshTriplett> See symbol.h.
-<JoshTriplett> "struct symbol" represents one symbol.
-<JoshTriplett> As with the various other structures, it has some common data and a union of sub-structures for the parts that differ between different types.
-<JoshTriplett> Most of the interesting bits come in the NS_SYMBOL case.
-<JoshTriplett> Among other things, it has a struct statement for the body of a function (if any), a list of symbols for the arguments, an expression for a variable initializer, and so on.
-<JoshTriplett> Together, struct symbol, struct statement, and struct expression represent most of the abstract syntax tree for C.
-<JoshTriplett> So, that represents most of the "front-end" of Sparse: parsing C and generating that abstract syntax tree.
-<JoshTriplett> That much occurs in pretty much any program using the Sparse frontend.
-<JoshTriplett> The backend varies among programs.
-<JoshTriplett> For instance, the c2xml backend goes that far, then outputs XML.
-<JoshTriplett> The sparse static analysis backend has a few steps: it generates linearized bytecode, does some evaluation on that, and outputs some warnings.
-<JoshTriplett> Several other backends run that linearized bytecode stage.
-<JoshTriplett> The linearized bytecode itself has a set of nested structures.
-<JoshTriplett> linearize.h defines all of them.
-<JoshTriplett> At the top level, it has struct entrypoint.
-<JoshTriplett> That represents an entrypoint to the code, which would normally mean a function.
-<JoshTriplett> An entrypoint has a list of basic blocks.
-<JoshTriplett> struct basic_block.
-<JoshTriplett> A basic block represents a series of instructions with no branches.
-<JoshTriplett> Straight-line code.
-<JoshTriplett> A branch only occurs at the end of a basic block, and branches can only target the beginning of a basic block.
-<JoshTriplett> Typically, a conditional will consist of a basic block leading up to the branch, a basic block for the true case, a basic block for the false case, and a basic block where the two paths merge back together.
-<JoshTriplett> Either the true or the false case may not exist.
-<JoshTriplett> A loop will normally have a basic block for the loop body, which can branch to the top at the end or continue to the next basic block.
-<JoshTriplett> So basic blocks represent a node in the control flow graph.
-<JoshTriplett> The edges in that graph lead from one basic block to a basic block which can follow it in the execution of the program.
-<JoshTriplett> Each basic block has a series of instructions, "struct instruction".
-<JoshTriplett> "enum opcode" lists all the instructions.
-<JoshTriplett> Fairly high-level instruction set, corresponding directly to bits of C.
-<JoshTriplett> So you have an entrypoint, which has a graph of basic blocks, each of which has a list of instructions.
-<JoshTriplett> An entrypoint also has a pointer to the first instruction.
-<JoshTriplett> One last bit of trickiness: struct pseudo.
-<JoshTriplett> Have you ever heard of "static single assignment" or SSA form?
-<JoshTriplett> struct pseudo represents one of those single-assignment variables.
-<JoshTriplett> Each one has a pointer to the symbol it represents (which may have many pseudos referencing it).
-<JoshTriplett> Each one also has a pointer to the instruction that defines it.
-<JoshTriplett> That covers most of the major data structures in Sparse.
-<JoshTriplett> Now, given all that, some of the top-level stuff in sparse.c may make more sense.
-<JoshTriplett> For instance, the context checking works in terms of basic blocks.
-<JoshTriplett> Hopefully some of that helped you understand Sparse better.
-
+As far as the parsing structures go...
+The C parser exists in two main files: parse.c, which parses statements, and expression.c, which parses expressions.
+parse.h contains the definition of struct statement, which represents a C statement.
+That includes only those things which can't appear as an expression, which primarily includes control flow statements such as if, loops, switch/case, and goto.
+expression.h contains the definition of struct expression, which represents a C expression. That has a lot more content, since most C constructs can appear in expressions.
+A series of statements forms a compound statement (STMT_COMPOUND).
+That appears as another struct statement which has a statement_list member.
+A function body consists of a compound statement.
+When you look at a loop body, if or else body, or case body, you'll notice that they just have a struct statement, not a statement_list; they can have multiple statements by using a compound statement.
+Also note that all loops get turned into a single "iterator" statement.
+for, while, and do-while.
+A symbol, then, represents a name in a C file. A symbol might represent a variable, a function, a label, or various other things.
+See symbol.h.
+"struct symbol" represents one symbol.
+As with the various other structures, it has some common data and a union of sub-structures for the parts that differ between different types.
+Most of the interesting bits come in the NS_SYMBOL case.
+Among other things, it has a struct statement for the body of a function (if any), a list of symbols for the arguments, an expression for a variable initializer, and so on.
+Together, struct symbol, struct statement, and struct expression represent most of the abstract syntax tree for C.
+So, that represents most of the "front-end" of Sparse: parsing C and generating that abstract syntax tree.
+That much occurs in pretty much any program using the Sparse frontend.
+The backend varies among programs.
+For instance, the c2xml backend goes that far, then outputs XML.
+The sparse static analysis backend has a few steps: it generates linearized bytecode, does some evaluation on that, and outputs some warnings.
+Several other backends run that linearized bytecode stage.
+The linearized bytecode itself has a set of nested structures.
+linearize.h defines all of them.
+At the top level, it has struct entrypoint.
+That represents an entrypoint to the code, which would normally mean a function.
+An entrypoint has a list of basic blocks.
+struct basic_block.
+A basic block represents a series of instructions with no branches.
+Straight-line code.
+A branch only occurs at the end of a basic block, and branches can only target the beginning of a basic block.
+Typically, a conditional will consist of a basic block leading up to the branch, a basic block for the true case, a basic block for the false case, and a basic block where the two paths merge back together.
+Either the true or the false case may not exist.
+A loop will normally have a basic block for the loop body, which can branch to the top at the end or continue to the next basic block.
+So basic blocks represent a node in the control flow graph.
+The edges in that graph lead from one basic block to a basic block which can follow it in the execution of the program.
+Each basic block has a series of instructions, "struct instruction".
+"enum opcode" lists all the instructions.
+Fairly high-level instruction set, corresponding directly to bits of C.
+So you have an entrypoint, which has a graph of basic blocks, each of which has a list of instructions.
+An entrypoint also has a pointer to the first instruction.
+One last bit of trickiness: struct pseudo.
+Have you ever heard of "static single assignment" or SSA form?
+struct pseudo represents one of those single-assignment variables.
+Each one has a pointer to the symbol it represents (which may have many pseudos referencing it).
+Each one also has a pointer to the instruction that defines it.
+That covers most of the major data structures in Sparse.
+Now, given all that, some of the top-level stuff in sparse.c may make more sense.
+For instance, the context checking works in terms of basic blocks.
+Hopefully some of that helped you understand Sparse better.
diff --git a/Documentation/test-suite b/Documentation/test-suite
index 160fed31..1315dbd6 100644
--- a/Documentation/test-suite
+++ b/Documentation/test-suite
@@ -40,7 +40,7 @@ check-output-start / check-output-end
check-output-ignore / check-error-ignore
Don't check the expected output (stdout or stderr) of check-command
- (usefull when this output is not comparable or if you're only interested
+ (useful when this output is not comparable or if you're only interested
in the exit value).
By default this check is done.
@@ -60,8 +60,8 @@ check-output-excludes: <pattern>
check-output-pattern(<nbr>): <pattern>
check-output-pattern(<min>,<max>): <pattern>
- Similar to the '-contains/excludes' here above, but with full control
- of the number of times the pattern should occurs in the output.
+ Similar to the contains/excludes above, but with full control
+ of the number of times the pattern should occur in the output.
If <min> or <max> is '-' the corresponding check is ignored.
Using test-suite
@@ -91,7 +91,7 @@ cmd:
"sparse $file".
The output of the test-suite format command can be redirected into the
-test case to create a test-suite formated file.
+test case to create a test-suite formatted file.
$ ./test-suite format bad-assignment.c Assignment >> bad-assignment.c
$ cat !$
diff --git a/evaluate.c b/evaluate.c
index 4be4e8e5..bd10c6d9 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -47,6 +47,17 @@ struct symbol *current_fn;
static struct symbol *degenerate(struct expression *expr);
static struct symbol *evaluate_symbol(struct symbol *sym);
+static inline int valid_expr_type(struct expression *expr)
+{
+ return expr && valid_type(expr->ctype);
+}
+
+static inline int valid_subexpr_type(struct expression *expr)
+{
+ return valid_expr_type(expr->left)
+ && valid_expr_type(expr->right);
+}
+
static struct symbol *evaluate_symbol_expression(struct expression *expr)
{
struct expression *addr;
@@ -393,15 +404,20 @@ static inline int is_string_type(struct symbol *type)
static struct symbol *bad_expr_type(struct expression *expr)
{
- sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
switch (expr->type) {
case EXPR_BINOP:
case EXPR_COMPARE:
+ if (!valid_subexpr_type(expr))
+ break;
+ sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
info(expr->pos, " left side has type %s", show_typename(expr->left->ctype));
info(expr->pos, " right side has type %s", show_typename(expr->right->ctype));
break;
case EXPR_PREOP:
case EXPR_POSTOP:
+ if (!valid_expr_type(expr->unop))
+ break;
+ sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op));
info(expr->pos, " argument has type %s", show_typename(expr->unop->ctype));
break;
default:
@@ -847,8 +863,10 @@ static struct symbol *evaluate_ptr_sub(struct expression *expr)
val->value = value;
if (value & (value-1)) {
- if (Wptr_subtraction_blows)
+ if (Wptr_subtraction_blows) {
warning(expr->pos, "potentially expensive pointer subtraction");
+ info(expr->pos, " '%s' has a non-power-of-2 size: %lu", show_typename(lbase), value);
+ }
}
sub->op = '-';
@@ -877,23 +895,23 @@ static struct symbol *evaluate_conditional(struct expression *expr, int iterator
warning(expr->pos, "assignment expression in conditional");
ctype = evaluate_expression(expr);
- if (ctype) {
- if (is_safe_type(ctype))
- warning(expr->pos, "testing a 'safe expression'");
- if (is_func_type(ctype)) {
- if (Waddress)
- warning(expr->pos, "the address of %s will always evaluate as true", "a function");
- } else if (is_array_type(ctype)) {
- if (Waddress)
- warning(expr->pos, "the address of %s will always evaluate as true", "an array");
- } else if (!is_scalar_type(ctype)) {
- sparse_error(expr->pos, "incorrect type in conditional");
- info(expr->pos, " got %s", show_typename(ctype));
- ctype = NULL;
- }
+ if (!valid_type(ctype))
+ return NULL;
+ if (is_safe_type(ctype))
+ warning(expr->pos, "testing a 'safe expression'");
+ if (is_func_type(ctype)) {
+ if (Waddress)
+ warning(expr->pos, "the address of %s will always evaluate as true", "a function");
+ } else if (is_array_type(ctype)) {
+ if (Waddress)
+ warning(expr->pos, "the address of %s will always evaluate as true", "an array");
+ } else if (!is_scalar_type(ctype)) {
+ sparse_error(expr->pos, "incorrect type in conditional");
+ info(expr->pos, " got %s", show_typename(ctype));
+ return NULL;
}
- ctype = degenerate(expr);
+ ctype = degenerate(expr);
return ctype;
}
@@ -3187,9 +3205,9 @@ struct symbol *evaluate_expression(struct expression *expr)
case EXPR_SYMBOL:
return evaluate_symbol_expression(expr);
case EXPR_BINOP:
- if (!evaluate_expression(expr->left))
- return NULL;
- if (!evaluate_expression(expr->right))
+ evaluate_expression(expr->left);
+ evaluate_expression(expr->right);
+ if (!valid_subexpr_type(expr))
return NULL;
return evaluate_binop(expr);
case EXPR_LOGICAL:
@@ -3200,15 +3218,15 @@ struct symbol *evaluate_expression(struct expression *expr)
return NULL;
return evaluate_comma(expr);
case EXPR_COMPARE:
- if (!evaluate_expression(expr->left))
- return NULL;
- if (!evaluate_expression(expr->right))
+ evaluate_expression(expr->left);
+ evaluate_expression(expr->right);
+ if (!valid_subexpr_type(expr))
return NULL;
return evaluate_compare(expr);
case EXPR_ASSIGNMENT:
- if (!evaluate_expression(expr->left))
- return NULL;
- if (!evaluate_expression(expr->right))
+ evaluate_expression(expr->left);
+ evaluate_expression(expr->right);
+ if (!valid_subexpr_type(expr))
return NULL;
return evaluate_assignment(expr);
case EXPR_PREOP:
diff --git a/lib.c b/lib.c
index 0fe7fd36..fcd31e84 100644
--- a/lib.c
+++ b/lib.c
@@ -682,6 +682,7 @@ static char **handle_onoff_switch(char *arg, char **next, const struct flag warn
if (*warnings[i].flag != WARNING_FORCE_OFF && warnings[i].flag != &Wsparse_error)
*warnings[i].flag = WARNING_ON;
}
+ return NULL;
}
// Prefixes "no" and "no-" mean to turn warning off.
diff --git a/linearize.c b/linearize.c
index b1a1dd4b..3b4b0d9b 100644
--- a/linearize.c
+++ b/linearize.c
@@ -1277,10 +1277,8 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi
struct symbol *fntype;
struct context *context;
- if (!expr->ctype) {
- warning(expr->pos, "call with no type!");
+ if (!expr->ctype)
return VOID;
- }
fn = expr->fn;
fntype = fn->ctype;
diff --git a/simplify.c b/simplify.c
index 814b57bb..8aac852b 100644
--- a/simplify.c
+++ b/simplify.c
@@ -393,6 +393,131 @@ static unsigned int operand_size(struct instruction *insn, pseudo_t pseudo)
return size;
}
+static pseudo_t eval_insn(struct instruction *insn)
+{
+ /* FIXME! Verify signs and sizes!! */
+ unsigned int size = insn->size;
+ long long left = insn->src1->value;
+ long long right = insn->src2->value;
+ unsigned long long ul, ur;
+ long long res, mask, bits;
+
+ mask = 1ULL << (size-1);
+ bits = mask | (mask-1);
+
+ if (left & mask)
+ left |= ~bits;
+ if (right & mask)
+ right |= ~bits;
+ ul = left & bits;
+ ur = right & bits;
+
+ switch (insn->opcode) {
+ case OP_ADD:
+ res = left + right;
+ break;
+ case OP_SUB:
+ res = left - right;
+ break;
+ case OP_MULU:
+ res = ul * ur;
+ break;
+ case OP_MULS:
+ res = left * right;
+ break;
+ case OP_DIVU:
+ if (!ur)
+ goto undef;
+ res = ul / ur;
+ break;
+ case OP_DIVS:
+ if (!right)
+ goto undef;
+ if (left == mask && right == -1)
+ goto undef;
+ res = left / right;
+ break;
+ case OP_MODU:
+ if (!ur)
+ goto undef;
+ res = ul % ur;
+ break;
+ case OP_MODS:
+ if (!right)
+ goto undef;
+ if (left == mask && right == -1)
+ goto undef;
+ res = left % right;
+ break;
+ case OP_SHL:
+ res = left << right;
+ break;
+ case OP_LSR:
+ res = ul >> ur;
+ break;
+ case OP_ASR:
+ res = left >> right;
+ break;
+ /* Logical */
+ case OP_AND:
+ res = left & right;
+ break;
+ case OP_OR:
+ res = left | right;
+ break;
+ case OP_XOR:
+ res = left ^ right;
+ break;
+ case OP_AND_BOOL:
+ res = left && right;
+ break;
+ case OP_OR_BOOL:
+ res = left || right;
+ break;
+
+ /* Binary comparison */
+ case OP_SET_EQ:
+ res = left == right;
+ break;
+ case OP_SET_NE:
+ res = left != right;
+ break;
+ case OP_SET_LE:
+ res = left <= right;
+ break;
+ case OP_SET_GE:
+ res = left >= right;
+ break;
+ case OP_SET_LT:
+ res = left < right;
+ break;
+ case OP_SET_GT:
+ res = left > right;
+ break;
+ case OP_SET_B:
+ res = ul < ur;
+ break;
+ case OP_SET_A:
+ res = ul > ur;
+ break;
+ case OP_SET_BE:
+ res = ul <= ur;
+ break;
+ case OP_SET_AE:
+ res = ul >= ur;
+ break;
+ default:
+ return NULL;
+ }
+ res &= bits;
+
+ return value_pseudo(res);
+
+undef:
+ return NULL;
+}
+
+
static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long value)
{
unsigned int size = operand_size(insn, pseudo);
@@ -548,122 +673,12 @@ static int simplify_constant_leftside(struct instruction *insn)
static int simplify_constant_binop(struct instruction *insn)
{
- /* FIXME! Verify signs and sizes!! */
- long long left = insn->src1->value;
- long long right = insn->src2->value;
- unsigned long long ul, ur;
- long long res, mask, bits;
-
- mask = 1ULL << (insn->size-1);
- bits = mask | (mask-1);
-
- if (left & mask)
- left |= ~bits;
- if (right & mask)
- right |= ~bits;
- ul = left & bits;
- ur = right & bits;
+ pseudo_t res = eval_insn(insn);
- switch (insn->opcode) {
- case OP_ADD:
- res = left + right;
- break;
- case OP_SUB:
- res = left - right;
- break;
- case OP_MULU:
- res = ul * ur;
- break;
- case OP_MULS:
- res = left * right;
- break;
- case OP_DIVU:
- if (!ur)
- return 0;
- res = ul / ur;
- break;
- case OP_DIVS:
- if (!right)
- return 0;
- if (left == mask && right == -1)
- return 0;
- res = left / right;
- break;
- case OP_MODU:
- if (!ur)
- return 0;
- res = ul % ur;
- break;
- case OP_MODS:
- if (!right)
- return 0;
- if (left == mask && right == -1)
- return 0;
- res = left % right;
- break;
- case OP_SHL:
- res = left << right;
- break;
- case OP_LSR:
- res = ul >> ur;
- break;
- case OP_ASR:
- res = left >> right;
- break;
- /* Logical */
- case OP_AND:
- res = left & right;
- break;
- case OP_OR:
- res = left | right;
- break;
- case OP_XOR:
- res = left ^ right;
- break;
- case OP_AND_BOOL:
- res = left && right;
- break;
- case OP_OR_BOOL:
- res = left || right;
- break;
-
- /* Binary comparison */
- case OP_SET_EQ:
- res = left == right;
- break;
- case OP_SET_NE:
- res = left != right;
- break;
- case OP_SET_LE:
- res = left <= right;
- break;
- case OP_SET_GE:
- res = left >= right;
- break;
- case OP_SET_LT:
- res = left < right;
- break;
- case OP_SET_GT:
- res = left > right;
- break;
- case OP_SET_B:
- res = ul < ur;
- break;
- case OP_SET_A:
- res = ul > ur;
- break;
- case OP_SET_BE:
- res = ul <= ur;
- break;
- case OP_SET_AE:
- res = ul >= ur;
- break;
- default:
+ if (!res)
return 0;
- }
- res &= bits;
- replace_with_pseudo(insn, value_pseudo(res));
+ replace_with_pseudo(insn, res);
return REPEAT_CSE;
}
diff --git a/sparse.1 b/sparse.1
index 01d36b33..88343f31 100644
--- a/sparse.1
+++ b/sparse.1
@@ -62,7 +62,7 @@ arithmetic operations other than bitwise operations, and on any conversion of
one restricted type into another, except via a cast that includes
\fB__attribute__((force))\fR.
-__bitwise ends up being a "stronger integer separation". That one
+__bitwise ends up being a "stronger integer separation", one that
doesn't allow you to mix with non-bitwise integers, so now it's much
harder to lose the type by mistake.
@@ -210,7 +210,7 @@ Sparse issues these warnings by default. To turn them off, use
.B \-Winit\-cstring
Warn about initialization of a char array with a too long constant C string.
-If the size of the char array and the length of the string is the same,
+If the size of the char array and the length of the string are the same,
there is no space for the last nul char of the string in the array:
.nf
@@ -354,7 +354,7 @@ Warn about preprocessor conditionals that use the value of an undefined
preprocessor symbol.
Standard C (C99 6.10.1) permits using the value of an undefined preprocessor
-symbol in preprocessor conditionals, and specifies it has have a value of 0.
+symbol in preprocessor conditionals, and specifies it has a value of 0.
However, this behavior can lead to subtle errors.
Sparse does not issue these warnings by default.
@@ -371,6 +371,7 @@ The \fIdir\fR name would normally take the form of the target's
normalized GNU triplet. (e.g. i386-linux-gnu).
.
.SH DEBUG OPTIONS
+.TP
.B \-fmem-report
Report some statistics about memory allocation used by the tool.
.
diff --git a/symbol.c b/symbol.c
index e87cd1cb..7e46ba9c 100644
--- a/symbol.c
+++ b/symbol.c
@@ -496,7 +496,9 @@ struct symbol *examine_symbol_type(struct symbol * sym)
sym->ctype.base_type = base;
return examine_node_type(sym);
}
- break;
+ sym->type = SYM_NODE;
+ sym->ctype.base_type = &bad_ctype;
+ return sym;
}
case SYM_PREPROCESSOR:
sparse_error(sym->pos, "ctype on preprocessor command? (%s)", show_ident(sym->ident));
diff --git a/symbol.h b/symbol.h
index fd574642..b4d1c2ac 100644
--- a/symbol.h
+++ b/symbol.h
@@ -309,6 +309,11 @@ extern void debug_symbol(struct symbol *);
extern void merge_type(struct symbol *sym, struct symbol *base_type);
extern void check_declaration(struct symbol *sym);
+static inline int valid_type(const struct symbol *ctype)
+{
+ return ctype && ctype != &bad_ctype;
+}
+
static inline struct symbol *get_base_type(const struct symbol *sym)
{
return examine_symbol_type(sym->ctype.base_type);
diff --git a/validation/bad-type-twice0.c b/validation/bad-type-twice0.c
new file mode 100644
index 00000000..7a9073c5
--- /dev/null
+++ b/validation/bad-type-twice0.c
@@ -0,0 +1,13 @@
+static int foo(a)
+{
+ return a ? : 1;
+}
+
+/*
+ * check-name: bad-type-twice0
+ *
+ * check-error-start
+bad-type-twice0.c:3:16: error: incorrect type in conditional
+bad-type-twice0.c:3:16: got incomplete type a
+ * check-error-end
+ */
diff --git a/validation/bad-type-twice1.c b/validation/bad-type-twice1.c
new file mode 100644
index 00000000..95cfd9e0
--- /dev/null
+++ b/validation/bad-type-twice1.c
@@ -0,0 +1,16 @@
+static unsigned long foo(unsigned long val, void *ref)
+{
+ if (val >= ref)
+ val = 0;
+ return val;
+}
+
+/*
+ * check-name: bad-type-twice1
+ *
+ * check-error-start
+bad-type-twice1.c:3:17: error: incompatible types for operation (>=)
+bad-type-twice1.c:3:17: left side has type unsigned long [unsigned] val
+bad-type-twice1.c:3:17: right side has type void *ref
+ * check-error-end
+ */
diff --git a/validation/bad-type-twice2.c b/validation/bad-type-twice2.c
new file mode 100644
index 00000000..0aadd7a3
--- /dev/null
+++ b/validation/bad-type-twice2.c
@@ -0,0 +1,18 @@
+extern type_t fun(int);
+
+int foo(int x, int y)
+{
+ return ((int)fun(y)) + x;
+}
+
+/*
+ * check-name: bad-type-twice2
+ *
+ * check-error-start
+bad-type-twice2.c:1:8: warning: 'type_t' has implicit type
+bad-type-twice2.c:1:15: error: Expected ; at end of declaration
+bad-type-twice2.c:1:15: error: got fun
+bad-type-twice2.c:5:22: error: undefined identifier 'fun'
+bad-type-twice2.c:5:18: error: cast from unknown type
+ * check-error-end
+ */
diff --git a/validation/ptr-sub-blows.c b/validation/ptr-sub-blows.c
new file mode 100644
index 00000000..af3d79e7
--- /dev/null
+++ b/validation/ptr-sub-blows.c
@@ -0,0 +1,23 @@
+static int ok(int *a, int *b)
+{
+ return a - b;
+}
+
+struct s {
+ int a, b, c;
+};
+
+static int ko(struct s *a, struct s *b)
+{
+ return a - b;
+}
+
+/*
+ * check-name: ptr-sub-blows
+ * check-command: sparse -Wptr-subtraction-blows $file
+ *
+ * check-error-start
+ptr-sub-blows.c:12:18: warning: potentially expensive pointer subtraction
+ptr-sub-blows.c:12:18: 'struct s' has a non-power-of-2 size: 12
+ * check-error-end
+ */
diff --git a/validation/typeof-bad.c b/validation/typeof-bad.c
new file mode 100644
index 00000000..a9366bad
--- /dev/null
+++ b/validation/typeof-bad.c
@@ -0,0 +1,17 @@
+static typeof(undef) a;
+
+static int foo(void)
+{
+ return a;
+}
+
+/*
+ * check-name: typeof-bad
+ *
+ * check-error-start
+typeof-bad.c:1:15: error: undefined identifier 'undef'
+typeof-bad.c:5:16: warning: incorrect type in return expression (different base types)
+typeof-bad.c:5:16: expected int
+typeof-bad.c:5:16: got bad type static [toplevel] a
+ * check-error-end
+ */