diff options
| -rw-r--r-- | evaluate.c | 3 | ||||
| -rw-r--r-- | options.c | 8 | ||||
| -rw-r--r-- | options.h | 4 | ||||
| -rw-r--r-- | sparse.1 | 30 | ||||
| -rw-r--r-- | symbol.c | 67 | ||||
| -rw-r--r-- | symbol.h | 25 | ||||
| -rw-r--r-- | validation/flex-array-align.c | 18 | ||||
| -rw-r--r-- | validation/flex-array-array.c | 15 | ||||
| -rw-r--r-- | validation/flex-array-error.c | 26 | ||||
| -rw-r--r-- | validation/flex-array-nested.c | 29 | ||||
| -rw-r--r-- | validation/flex-array-sizeof.c | 18 | ||||
| -rw-r--r-- | validation/flex-array-union-array-no.c | 9 | ||||
| -rw-r--r-- | validation/flex-array-union-array-yes.c | 11 | ||||
| -rw-r--r-- | validation/flex-array-union-array.h | 11 |
14 files changed, 256 insertions, 18 deletions
@@ -2256,6 +2256,9 @@ static struct symbol *evaluate_sizeof(struct expression *expr) size = bits_in_char; } + if (has_flexible_array(type) && Wflexible_array_sizeof) + warning(expr->pos, "using sizeof on a flexible structure"); + if (is_array_type(type) && size < 0) { // VLA, 1-dimension only struct expression *base, *size; struct symbol *base_type; @@ -100,6 +100,10 @@ int Wdesignated_init = 1; int Wdo_while = 0; int Wenum_mismatch = 1; int Wexternal_function_has_definition = 1; +int Wflexible_array_array = 1; +int Wflexible_array_nested = 0; +int Wflexible_array_sizeof = 0; +int Wflexible_array_union = 0; int Wimplicit_int = 1; int Winit_cstring = 0; int Wint_to_pointer_cast = 1; @@ -840,6 +844,10 @@ static const struct flag warnings[] = { { "do-while", &Wdo_while }, { "enum-mismatch", &Wenum_mismatch }, { "external-function-has-definition", &Wexternal_function_has_definition }, + { "flexible-array-array", &Wflexible_array_array }, + { "flexible-array-nested", &Wflexible_array_nested }, + { "flexible-array-sizeof", &Wflexible_array_sizeof }, + { "flexible-array-union", &Wflexible_array_union }, { "implicit-int", &Wimplicit_int }, { "init-cstring", &Winit_cstring }, { "int-to-pointer-cast", &Wint_to_pointer_cast }, @@ -99,6 +99,10 @@ extern int Wdesignated_init; extern int Wdo_while; extern int Wenum_mismatch; extern int Wexternal_function_has_definition; +extern int Wflexible_array_array; +extern int Wflexible_array_nested; +extern int Wflexible_array_sizeof; +extern int Wflexible_array_union; extern int Wimplicit_int; extern int Winit_cstring; extern int Wint_to_pointer_cast; @@ -257,6 +257,36 @@ Sparse issues these warnings by default. To turn them off, use \fB\-Wno\-external\-function\-has\-definition\fR. . .TP +.B -Wflexible-array-array +Warn about arrays of structures containing a flexible array. + +Sparse issues these warnings by default. To turn them off, use +\fB-Wno-flexible-array-array\fR. +. +.TP +.B -Wflexible-array-nested +Warn about structures containing a flexible array being contained into +another structure, union or array. + +Sparse does not issue these warnings by default. +. +.TP +.B -Wflexible-array-sizeof +Warn about using the sizeof operator on a structure containing a flexible array, +possibly recursively. + +Sparse does not issue these warnings by default. +. +.TP +.B -Wflexible-array-union +Enable the warnings regarding flexible arrays and unions. +To have any effect, at least one of \fB-Wflexible-array-array\fR, +\fB-Wflexible-array-nested\fR or \fB-Wflexible-array-sizeof\fR must also +be enabled. + +Sparse does issue these warnings by default. +. +.TP .B \-Winit\-cstring Warn about initialization of a char array with a too long constant C string. @@ -87,6 +87,8 @@ struct struct_union_info { unsigned long max_align; unsigned long bit_size; int align_size; + char has_flex_array; + struct symbol *flex_array; }; /* @@ -94,13 +96,8 @@ struct struct_union_info { */ static void lay_out_union(struct symbol *sym, struct struct_union_info *info) { - examine_symbol_type(sym); - - // Unnamed bitfields do not affect alignment. - if (sym->ident || !is_bitfield_type(sym)) { - if (sym->ctype.alignment > info->max_align) - info->max_align = sym->ctype.alignment; - } + if (sym->bit_size < 0 && is_array_type(sym)) + sparse_error(sym->pos, "flexible array member '%s' in a union", show_ident(sym->ident)); if (sym->bit_size > info->bit_size) info->bit_size = sym->bit_size; @@ -125,24 +122,18 @@ static void lay_out_struct(struct symbol *sym, struct struct_union_info *info) unsigned long bit_size, align_bit_mask; int base_size; - examine_symbol_type(sym); - - // Unnamed bitfields do not affect alignment. - if (sym->ident || !is_bitfield_type(sym)) { - if (sym->ctype.alignment > info->max_align) - info->max_align = sym->ctype.alignment; - } - bit_size = info->bit_size; base_size = sym->bit_size; /* - * Unsized arrays cause us to not align the resulting - * structure size + * If the member is unsized, either it's a flexible array or + * it's invalid and a warning has already been issued. */ if (base_size < 0) { - info->align_size = 0; + if (!is_array_type(sym)) + return; base_size = 0; + info->flex_array = sym; } align_bit_mask = bytes_to_bits(sym->ctype.alignment) - 1; @@ -196,6 +187,20 @@ static struct symbol * examine_struct_union_type(struct symbol *sym, int advance sparse_error(member->pos, "member '%s' has __auto_type", show_ident(member->ident)); member->ctype.base_type = &incomplete_ctype; } + if (info.flex_array) + sparse_error(info.flex_array->pos, "flexible array member '%s' is not last", show_ident(info.flex_array->ident)); + examine_symbol_type(member); + + if (member->ctype.alignment > info.max_align) { + // Unnamed bitfields do not affect alignment. + if (member->ident || !is_bitfield_type(member)) + info.max_align = member->ctype.alignment; + } + + if (has_flexible_array(member)) + info.has_flex_array = 1; + if (has_flexible_array(member) && Wflexible_array_nested) + warning(sym->pos, "nested flexible arrays"); fn(member, &info); } END_FOR_EACH_PTR(member); @@ -206,6 +211,11 @@ static struct symbol * examine_struct_union_type(struct symbol *sym, int advance bit_align = bytes_to_bits(sym->ctype.alignment)-1; bit_size = (bit_size + bit_align) & ~bit_align; } + if (info.flex_array) { + info.has_flex_array = 1; + } + if (info.has_flex_array && (!is_union_type(sym) || Wflexible_array_union)) + sym->has_flex_array = 1; sym->bit_size = bit_size; return sym; } @@ -261,6 +271,8 @@ static struct symbol * examine_array_type(struct symbol *sym) bit_size = -1; } } + if (has_flexible_array(base_type) && Wflexible_array_array) + warning(sym->pos, "array of flexible structures"); alignment = base_type->ctype.alignment; if (!sym->ctype.alignment) sym->ctype.alignment = alignment; @@ -782,14 +794,17 @@ struct symbol bool_ctype, void_ctype, type_ctype, incomplete_ctype, label_ctype, bad_ctype, null_ctype; struct symbol autotype_ctype; +struct symbol schar_ptr_ctype, short_ptr_ctype; struct symbol int_ptr_ctype, uint_ptr_ctype; struct symbol long_ptr_ctype, ulong_ptr_ctype; struct symbol llong_ptr_ctype, ullong_ptr_ctype; +struct symbol size_t_ptr_ctype, intmax_ptr_ctype, ptrdiff_ptr_ctype; struct symbol float32_ctype, float32x_ctype; struct symbol float64_ctype, float64x_ctype; struct symbol float128_ctype; struct symbol const_void_ctype, const_char_ctype; struct symbol const_ptr_ctype, const_string_ctype; +struct symbol const_wchar_ctype, const_wstring_ctype; struct symbol zero_int; @@ -876,17 +891,24 @@ static const struct ctype_declare { { &null_ctype, T_PTR(&void_ctype) }, { &label_ctype, T_PTR(&void_ctype) }, { &lazy_ptr_ctype, T_PTR(&void_ctype) }, + { &schar_ptr_ctype, T_PTR(&schar_ctype) }, + { &short_ptr_ctype, T_PTR(&short_ctype) }, { &int_ptr_ctype, T_PTR(&int_ctype) }, { &uint_ptr_ctype, T_PTR(&uint_ctype) }, { &long_ptr_ctype, T_PTR(&long_ctype) }, { &ulong_ptr_ctype, T_PTR(&ulong_ctype) }, { &llong_ptr_ctype, T_PTR(&llong_ctype) }, { &ullong_ptr_ctype, T_PTR(&ullong_ctype) }, + { &size_t_ptr_ctype, T_PTR(&void_ctype) }, // will be adjusted + { &intmax_ptr_ctype, T_PTR(&void_ctype) }, // will be adjusted + { &ptrdiff_ptr_ctype, T_PTR(&void_ctype) }, // will be adjusted { &const_ptr_ctype, T_PTR(&const_void_ctype) }, { &const_string_ctype, T_PTR(&const_char_ctype) }, + { &const_wstring_ctype,T_PTR(&const_wchar_ctype) }, { &const_void_ctype, T_CONST(&void_ctype, NULL, NULL) }, { &const_char_ctype, T_CONST(&char_ctype, &bits_in_char, &max_int_alignment)}, + { &const_wchar_ctype, T_CONST(&int_ctype, NULL, NULL) }, { NULL, } }; @@ -931,4 +953,13 @@ void init_ctype(void) intptr_ctype = ssize_t_ctype; if (!uintptr_ctype) uintptr_ctype = size_t_ctype; + + size_t_ptr_ctype.ctype.base_type = size_t_ctype; + intmax_ptr_ctype.ctype.base_type = intmax_ctype; + ptrdiff_ptr_ctype.ctype.base_type = ptrdiff_ctype; + + const_wchar_ctype.ctype.base_type = wchar_ctype; + const_wchar_ctype.rank = wchar_ctype->rank; + const_wchar_ctype.ctype.alignment = wchar_ctype->ctype.alignment; + const_wchar_ctype.bit_size = wchar_ctype->bit_size; } @@ -185,6 +185,7 @@ struct symbol { examined:1, expanding:1, evaluated:1, + has_flex_array:1, string:1, designated_init:1, forced_arg:1, @@ -298,14 +299,17 @@ extern struct symbol bool_ctype, void_ctype, type_ctype, incomplete_ctype, label_ctype, bad_ctype, null_ctype; extern struct symbol autotype_ctype; +extern struct symbol schar_ptr_ctype, short_ptr_ctype; extern struct symbol int_ptr_ctype, uint_ptr_ctype; extern struct symbol long_ptr_ctype, ulong_ptr_ctype; extern struct symbol llong_ptr_ctype, ullong_ptr_ctype; +extern struct symbol size_t_ptr_ctype, intmax_ptr_ctype, ptrdiff_ptr_ctype; extern struct symbol float32_ctype, float32x_ctype; extern struct symbol float64_ctype, float64x_ctype; extern struct symbol float128_ctype; extern struct symbol const_void_ctype, const_char_ctype; extern struct symbol const_ptr_ctype, const_string_ctype; +extern struct symbol const_wchar_ctype, const_wstring_ctype; /* Special internal symbols */ extern struct symbol zero_int; @@ -421,6 +425,20 @@ static inline int is_array_type(struct symbol *type) return type->type == SYM_ARRAY; } +static inline int is_struct_type(struct symbol *type) +{ + if (type->type == SYM_NODE) + type = type->ctype.base_type; + return type->type == SYM_STRUCT; +} + +static inline int is_union_type(struct symbol *type) +{ + if (type->type == SYM_NODE) + type = type->ctype.base_type; + return type->type == SYM_UNION; +} + static inline int is_float_type(struct symbol *type) { if (type->type == SYM_NODE) @@ -506,6 +524,13 @@ static inline int is_extern_inline(struct symbol *sym) is_function(sym->ctype.base_type); } +static inline int has_flexible_array(struct symbol *type) +{ + if (type->type == SYM_NODE) + type = type->ctype.base_type; + return type->has_flex_array; +} + static inline int get_sym_type(struct symbol *type) { if (type->type == SYM_NODE) diff --git a/validation/flex-array-align.c b/validation/flex-array-align.c new file mode 100644 index 00000000..9f28942a --- /dev/null +++ b/validation/flex-array-align.c @@ -0,0 +1,18 @@ +struct s { + __INT32_TYPE__ x; + __INT16_TYPE__ y; + unsigned char f[]; +}; + +static int foo(struct s *s) +{ + return (sizeof(*s) << 16) | __builtin_offsetof(typeof(*s), f); +} + +/* + * check-name: flex-array-align + * check-command: test-linearize -Wno-flexible-array-sizeof $file + * + * check-output-ignore + * check-output-contains: ret\\..*\\$0x80006 + */ diff --git a/validation/flex-array-array.c b/validation/flex-array-array.c new file mode 100644 index 00000000..921a0698 --- /dev/null +++ b/validation/flex-array-array.c @@ -0,0 +1,15 @@ +struct s { + int i; + long f[]; +}; + +static struct s a[2]; + +/* + * check-name: flex-array-array + * check-command: sparse -Wflexible-array-array $file + * + * check-error-start +flex-array-array.c:6:18: warning: array of flexible structures + * check-error-end + */ diff --git a/validation/flex-array-error.c b/validation/flex-array-error.c new file mode 100644 index 00000000..2b7e6953 --- /dev/null +++ b/validation/flex-array-error.c @@ -0,0 +1,26 @@ +struct s { + int i; + long f[]; + int j; +}; + +union u { + int i; + long f[]; +}; + +// trigger the examination of the offending types +static int foo(struct s *s, union u *u) +{ + return __builtin_offsetof(typeof(*s), i) + + __builtin_offsetof(typeof(*u), i); +} + +/* + * check-name: flex-array-error + * + * check-error-start +flex-array-error.c:3:14: error: flexible array member 'f' is not last +flex-array-error.c:9:14: error: flexible array member 'f' in a union + * check-error-end + */ diff --git a/validation/flex-array-nested.c b/validation/flex-array-nested.c new file mode 100644 index 00000000..63767683 --- /dev/null +++ b/validation/flex-array-nested.c @@ -0,0 +1,29 @@ +struct f { + int i; + long f[]; +}; + +struct s { + struct f f; +}; + +union u { + struct f f; +}; + +// trigger the examination of the offending types +static int foo(struct s *s, union u *u) +{ + return __builtin_offsetof(typeof(*s), f) + + __builtin_offsetof(typeof(*u), f); +} + +/* + * check-name: flex-array-nested + * check-command: sparse -Wflexible-array-nested $file + * + * check-error-start +flex-array-nested.c:6:8: warning: nested flexible arrays +flex-array-nested.c:10:7: warning: nested flexible arrays + * check-error-end + */ diff --git a/validation/flex-array-sizeof.c b/validation/flex-array-sizeof.c new file mode 100644 index 00000000..05394e19 --- /dev/null +++ b/validation/flex-array-sizeof.c @@ -0,0 +1,18 @@ +struct s { + int i; + long f[]; +}; + +static int foo(struct s *s) +{ + return sizeof(*s); +} + +/* + * check-name: flex-array-sizeof + * check-command: sparse -Wflexible-array-sizeof $file + * + * check-error-start +flex-array-sizeof.c:8:16: warning: using sizeof on a flexible structure + * check-error-end + */ diff --git a/validation/flex-array-union-array-no.c b/validation/flex-array-union-array-no.c new file mode 100644 index 00000000..5a1de787 --- /dev/null +++ b/validation/flex-array-union-array-no.c @@ -0,0 +1,9 @@ +#include "flex-array-union-array.h" + +/* + * check-name: flex-array-union-no + * check-command: sparse -Wflexible-array-array -Wno-flexible-array-union $file + * + * check-error-start + * check-error-end + */ diff --git a/validation/flex-array-union-array-yes.c b/validation/flex-array-union-array-yes.c new file mode 100644 index 00000000..c2b71d65 --- /dev/null +++ b/validation/flex-array-union-array-yes.c @@ -0,0 +1,11 @@ +#include "flex-array-union-array.h" + +/* + * check-name: flex-array-union-yes + * check-command: sparse -Wflexible-array-array -Wflexible-array-union $file + * + * check-error-start +flex-array-union-array-yes.c: note: in included file: +flex-array-union-array.h:11:17: warning: array of flexible structures + * check-error-end + */ diff --git a/validation/flex-array-union-array.h b/validation/flex-array-union-array.h new file mode 100644 index 00000000..b2a74d1a --- /dev/null +++ b/validation/flex-array-union-array.h @@ -0,0 +1,11 @@ +struct s_flex { + int i; + long f[]; +}; + +union s { + struct s_flex flex; + char buf[200]; +}; + +static union s a[2]; |
