fix handling of address_space in casts and assignments
PATCH 1/1 fix handling of address_space in casts and assignments
Turn FORCE_MOD into storage class specifier (that's how it's actually used and that makes for much simpler logics).
Introduce explicit EXPR_FORCE_CAST for forced casts; handle it properly.
Kill the idiocy in get_as() (we end up picking the oddest things for address space - e.g. if we have int __attribute__((address_space(1))) *p, we'll get warnings about removal of address space when we do things like (unsigned short)*p. Fixed. BTW, that had caught a bunch of very odd bogosities in the kernel and eliminated several false positives in there.
As the result, get_as() is gone now and evaluate_cast() got simpler.
Kill the similar idiocy in handling pointer assignments; while we are at it, fix the qualifiers check for assignments to/from void * (you can't assign const int * to void * - qualifiers on the left side should be no less than on the right one; for normal codepath we get that checked, but the special case of void * skips these checks).
--- compile-i386.c | 1 + dissect.c | 2 +- evaluate.c | 91 +++++++++++++++++++++++--------------------------------- expand.c | 1 + expression.c | 18 ++++++++--- expression.h | 3 +- inline.c | 1 + linearize.c | 1 + parse.c | 7 +++- show-parse.c | 1 + symbol.h | 4 +- 11 files changed, 65 insertions(+), 65 deletions(-)
compile-i386.c +1 -0
@@ -2351,6 +2351,7 @@ static struct storage *x86_expression(struct expression *expr)warning (expr->pos,"invalid expression after evaluation" );return NULL ;case EXPR_CAST : +case EXPR_FORCE_CAST :case EXPR_IMPLIED_CAST :return emit_cast_expr (expr);case EXPR_VALUE :
dissect.c +1 -1
@@ -317,7 +317,7 @@ again:do_expression (U_VOID , expr->left); ret =do_expression (mode, expr->right); -break ;case EXPR_CAST ://case EXPR_IMPLIED_CAST: +break ;case EXPR_CAST :case EXPR_FORCE_CAST ://case EXPR_IMPLIED_CAST: ret =base_type (expr->cast_type);do_initializer (ret, expr->cast_expression);
evaluate.c +37 -54
155 lines not on this page · raw message
expand.c +1 -0
@@ -955,6 +955,7 @@ static int expand_expression(struct expression *expr)return expand_postop (expr);case EXPR_CAST : +case EXPR_FORCE_CAST :case EXPR_IMPLIED_CAST :return expand_cast (expr);
expression.c +13 -5
@@ -118,7 +118,7 @@ static struct token *parse_type(struct token *token, struct expression **tree)struct symbol *sym; *tree =alloc_expression (token->pos,EXPR_TYPE ); (*tree)->flags = Int_const_expr;/* sic */ - token =typename (token, &sym); + token =typename (token, &sym,0 );if (sym->ident)sparse_error (token->pos, "type expression should not include identifier "
@@ -167,7 +167,7 @@ static struct token *builtin_offsetof_expr(struct token *token,return expect (token,'(' ,"after __builtin_offset" ); token = token->next; - token =typename (token, &sym); + token =typename (token, &sym,0 );if (sym->ident)sparse_error (token->pos, "type expression should not include identifier "
@@ -482,7 +482,7 @@ struct token *primary_expression(struct token *token, struct expression **tree)if (token->special =='[' &&lookup_type (token->next)) { expr =alloc_expression (token->pos,EXPR_TYPE ); expr->flags = Int_const_expr;/* sic */ - token =typename (token->next, &expr->symbol); + token =typename (token->next, &expr->symbol,0 ); token =expect (token,']' ,"in type expression" );break ; }
@@ -600,7 +600,7 @@ static struct token *type_info_expression(struct token *token, token = token->next;if (!match_op (token,'(' ) || !lookup_type (token->next))return unary_expression (token, &expr->cast_expression); - token =typename (token->next, &expr->cast_type); + token =typename (token->next, &expr->cast_type,0 );if (!match_op (token,')' )) {static const char * error[] = {
@@ -715,15 +715,23 @@ static struct token *cast_expression(struct token *token, struct expression **trstruct expression *cast =alloc_expression (next->pos,EXPR_CAST );struct expression *v;struct symbol *sym; +int is_force; - token =typename (next, &sym); + token =typename (next, &sym,MOD_FORCE ); cast->cast_type = sym; + is_force = sym->ctype.modifiers &MOD_FORCE ; + sym->ctype.modifiers &= ~MOD_FORCE ; token =expect (token,')' ,"at end of cast operator" );if (match_op (token,'{' )) { +if (is_force) +warning (sym->pos, +"[force] in compound literal" ); token =initializer (&cast->cast_expression, token);return postfix_expression (token, tree, cast); } *tree = cast; +if (is_force) + cast->type =EXPR_FORCE_CAST ; token =cast_expression (token, &v);if (!v)return token;
expression.h +2 -1
@@ -27,6 +27,7 @@ enum expression_type {EXPR_PREOP ,EXPR_POSTOP ,EXPR_CAST , +EXPR_FORCE_CAST ,EXPR_IMPLIED_CAST ,EXPR_SIZEOF , EXPR_ALIGNOF,
@@ -190,7 +191,7 @@ static inline struct expression *alloc_const_expression(struct position pos, int }/* Type name parsing */ -struct token *typename (struct token *,struct symbol **); +struct token *typename (struct token *,struct symbol **,int );static inline int lookup_type (struct token *token) {
inline.c +1 -0
@@ -145,6 +145,7 @@ static struct expression * copy_expression(struct expression *expr) *expr->cast_type = *sym;break ; } +case EXPR_FORCE_CAST :case EXPR_IMPLIED_CAST :case EXPR_SIZEOF :case EXPR_PTRSIZEOF :
linearize.c +1 -0
@@ -1581,6 +1581,7 @@ pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr)return linearize_postop (ep, expr);case EXPR_CAST : +case EXPR_FORCE_CAST :case EXPR_IMPLIED_CAST :return linearize_cast (ep, expr);
parse.c +5 -2
@@ -768,7 +768,7 @@ static struct token *typeof_specifier(struct token *token, struct ctype *ctype)return token; }if (lookup_type (token->next)) { - token =typename (token->next, &sym); + token =typename (token->next, &sym,0 ); *ctype = sym->ctype; }else {struct symbol *typeof_sym =alloc_symbol (token->pos,SYM_TYPEOF );
@@ -1343,13 +1343,16 @@ static struct token *parameter_declaration(struct token *token, struct symbol **return token; } -struct token *typename (struct token *token,struct symbol **p) +struct token *typename (struct token *token,struct symbol **p,int mod) {struct symbol *sym =alloc_symbol (token->pos,SYM_NODE ); *p = sym; token =declaration_specifiers (token, &sym->ctype,0 ); token =declarator (token, sym,NULL );apply_modifiers (token->pos, &sym->ctype); +if (sym->ctype.modifiers &MOD_STORAGE & ~mod) +warning (sym->pos,"storage class in typename (%s)" , +show_typename (sym));return token; }
show-parse.c +1 -0
@@ -1053,6 +1053,7 @@ int show_expression(struct expression *expr)warning (expr->pos,"invalid expression after evaluation" );return 0 ;case EXPR_CAST : +case EXPR_FORCE_CAST :case EXPR_IMPLIED_CAST :return show_cast_expr (expr);case EXPR_VALUE :
symbol.h +2 -2
@@ -204,12 +204,12 @@ struct symbol {#define MOD_BITWISE 0x80000000#define MOD_NONLOCAL (MOD_EXTERN | MOD_TOPLEVEL) -#define MOD_STORAGE (MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL) +#define MOD_STORAGE (MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL | MOD_FORCE)#define MOD_SIGNEDNESS (MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED)#define MOD_SPECIFIER (MOD_CHAR | MOD_SHORT | MOD_LONG | MOD_LONGLONG | MOD_SIGNEDNESS)#define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG | MOD_LONGLONG)#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE | \ - MOD_ASSIGNED | MOD_USERTYPE | MOD_FORCE | MOD_ACCESSED | MOD_EXPLICITLY_SIGNED) + MOD_ASSIGNED | MOD_USERTYPE | MOD_ACCESSED | MOD_EXPLICITLY_SIGNED)#define MOD_PTRINHERIT (MOD_VOLATILE | MOD_CONST | MOD_NODEREF | MOD_STORAGE)
Signature · 1 line
1.5.0-rc2.GIT
PATCH 1/1 fix handling of pointers in ?:
a) qualifiers are joined (const int * / volatile int * -> const volatile int *)
b) pointer to void / pointer to T => pointer to void (with all qualifiers)
testcase added
Still missing: T1 * / T2 * => pointer to composite type of T1 and T2
--- evaluate.c | 82 ++++++++++++++++++++++++++++------------------- validation/cond_expr2.c | 23 +++++++++++++ 2 files changed, 72 insertions(+), 33 deletions(-) create mode 100644 validation/cond_expr2.c
evaluate.c +49 -33
@@ -1070,31 +1070,6 @@ OK: }/* -* FIXME!! This should do casts, array degeneration etc.. -*/ -static struct symbol *compatible_ptr_type (struct expression *left,struct expression *right) -{ -struct symbol *ltype = left->ctype, *rtype = right->ctype; - -if (ltype->type ==SYM_NODE ) - ltype = ltype->ctype.base_type; - -if (rtype->type ==SYM_NODE ) - rtype = rtype->ctype.base_type; - -if (ltype->type ==SYM_PTR ) { -if (rtype->ctype.base_type == &void_ctype) -return ltype; - } - -if (rtype->type ==SYM_PTR ) { -if (ltype->ctype.base_type == &void_ctype) -return rtype; - } -return NULL ; -} - -/* * NOTE! The degenerate case of "x ? : y", where we don't * have a true case, this will possibly promote "x" to the * same type as "y", and thus _change_ the conditional
@@ -1104,9 +1079,10 @@ static struct symbol *compatible_ptr_type(struct expression *left, struct expresstatic struct symbol *evaluate_conditional_expression (struct expression *expr) {struct expression **true; -struct symbol *ctype, *ltype, *rtype; +struct symbol *ctype, *ltype, *rtype, *lbase, *rbase;int lclass, rclass;const char * typediff; +int qual;if (!evaluate_conditional (expr->conditional,0 ))return NULL ;
@@ -1141,9 +1117,11 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr) expr->cond_false =cast_to (expr->cond_false, ctype); goto out; } +if ((lclass | rclass) &TYPE_PTR ) {int is_null1 =is_null_pointer_constant (*true);int is_null2 =is_null_pointer_constant (expr->cond_false); +if (is_null1 && is_null2) { *true =cast_to (*true, &ptr_ctype); expr->cond_false =cast_to (expr->cond_false, &ptr_ctype);
@@ -1169,15 +1147,42 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr) goto Err; }/* OK, it's pointer on pointer */ -/* XXX - we need to handle qualifiers */ - ctype =compatible_ptr_type (*true, expr->cond_false); -if (ctype) - goto out; +if (ltype->ctype.as != rtype->ctype.as) { + typediff ="different address spaces" ; + goto Err; + } + +/* need to be lazier here */ + lbase =get_base_type (ltype); + rbase =get_base_type (rtype); + qual = ltype->ctype.modifiers | rtype->ctype.modifiers; + qual &=MOD_CONST |MOD_VOLATILE ; + +if (lbase == &void_ctype) { +/* XXX: pointers to function should warn here */ + ctype = ltype; + goto Qual; + + } +if (rbase == &void_ctype) { +/* XXX: pointers to function should warn here */ + ctype = rtype; + goto Qual; + } +/* XXX: that should be pointer to composite */ + ctype = ltype; + typediff =type_difference (lbase, rbase,MOD_IGN ,MOD_IGN ); +if (!typediff) + goto Qual; + goto Err; } - ctype = ltype; - typediff =type_difference (ltype, rtype,MOD_IGN ,MOD_IGN ); -if (!typediff) + +/* void on void, struct on same struct, union on same union */ +if (ltype == rtype) { + ctype = ltype; goto out; + } + typediff ="different base types" ; Err:expression_error (expr,"incompatible types in conditional expression (%s)" , typediff);
@@ -1186,6 +1191,17 @@ Err: out: expr->ctype = ctype;return ctype; + +Qual: +if (qual & ~ctype->ctype.modifiers) { +struct symbol *sym =alloc_symbol (ctype->pos,SYM_PTR ); + *sym = *ctype; + sym->ctype.modifiers |= qual; + ctype = sym; + } + *true =cast_to (*true, ctype); + expr->cond_false =cast_to (expr->cond_false, ctype); + goto out; }/* FP assignments can not do modulo or bit operations */
validation/cond_expr2.c new file +23 -0
@@ -0,0 +1,23 @@ +extern const int *p; +extern volatile void *q; +extern volatile int *r; +static void f (void ) +{ + q =1 ? p : q;// warn: const volatile void * -> const int * + r =1 ? r : q;// OK: volatile void * -> volatile int * + r =1 ? r : p;// warn: const volatile int * -> volatile int * +} +/* +* check-name: type of conditional expression +* check-description: Used to miss qualifier mixing and mishandle void * +* check-command: sparse $file +* +* check-output-start +cond_expr2.c:6:4: warning: incorrect type in assignment (different modifiers) +cond_expr2.c:6:4: expected void volatile *extern [addressable] [toplevel] q +cond_expr2.c:6:4: got void const volatile * +cond_expr2.c:8:4: warning: incorrect type in assignment (different modifiers) +cond_expr2.c:8:4: expected int volatile *extern [addressable] [toplevel] [assigned] r +cond_expr2.c:8:4: got int const volatile * +* check-output-end +*/
Signature · 1 line
1.5.0-rc2.GIT
Re: [PATCH] fix handling of pointers in ?:
Quoted 4 lines · Al Viro
a) qualifiers are joined (const int * / volatile int * -> const volatile int *)
b) pointer to void / pointer to T => pointer to void (with all qualifiers)testcase added
Applied (yesterday); thanks!
- Josh Triplett
Quoted 12 lines · Al Viro
Turn
FORCE_MODinto storage class specifier (that's how it's actually used and that makes for much simpler logics).Introduce explicit
EXPR_FORCE_CASTfor forced casts; handle it properly.Kill the idiocy in
get_as()(we end up picking the oddest things for address space - e.g. if we have int __attribute__((address_space(1))) *p, we'll get warnings about removal of address space when we do things like (unsigned short)*p. Fixed. BTW, that had caught a bunch of very odd bogosities in the kernel and eliminated several false positives in there.
Quoted 7 lines
As the result,
get_as()is gone now andevaluate_cast()got simpler.Kill the similar idiocy in handling pointer assignments; while we are at it, fix the qualifiers check for assignments to/from void * (you can't assign const int * to void * - qualifiers on the left side should be no less than on the right one; for normal codepath we get that checked, but the special case of void * skips these checks).
Applied (yesterday); thanks!
- Josh Triplett