summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-10-06 02:31:25 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2020-10-06 02:31:25 +0200
commitc0e96d6d3b95ae3f34ca54720e8a1196b201e119 (patch)
tree7e103eecaa9a28cc0ef59e5c280eaaf18e0924f0
parentb9453d0493bc672af908f83483e708880617ba8e (diff)
parentce9cf5b77cd8da6797da79af1298ecd4ed170a4d (diff)
downloadsparse-c0e96d6d3b95ae3f34ca54720e8a1196b201e119.tar.gz
Merge branch 'flex-array-base'
-rw-r--r--evaluate.c3
-rw-r--r--options.c6
-rw-r--r--options.h3
-rw-r--r--sparse.121
-rw-r--r--symbol.c48
-rw-r--r--symbol.h8
-rw-r--r--validation/flex-array-align.c18
-rw-r--r--validation/flex-array-array.c15
-rw-r--r--validation/flex-array-error.c26
-rw-r--r--validation/flex-array-nested.c29
-rw-r--r--validation/flex-array-sizeof.c18
11 files changed, 177 insertions, 18 deletions
diff --git a/evaluate.c b/evaluate.c
index c1ef348a..cfbb6ada 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2253,6 +2253,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;
diff --git a/options.c b/options.c
index 294dfd3b..b46900b9 100644
--- a/options.c
+++ b/options.c
@@ -100,6 +100,9 @@ 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 Wimplicit_int = 1;
int Winit_cstring = 0;
int Wint_to_pointer_cast = 1;
@@ -840,6 +843,9 @@ 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 },
{ "implicit-int", &Wimplicit_int },
{ "init-cstring", &Winit_cstring },
{ "int-to-pointer-cast", &Wint_to_pointer_cast },
diff --git a/options.h b/options.h
index abdf0864..d23ed472 100644
--- a/options.h
+++ b/options.h
@@ -99,6 +99,9 @@ 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 Wimplicit_int;
extern int Winit_cstring;
extern int Wint_to_pointer_cast;
diff --git a/sparse.1 b/sparse.1
index 48dab7a9..9b1a59c6 100644
--- a/sparse.1
+++ b/sparse.1
@@ -257,6 +257,27 @@ 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 \-Winit\-cstring
Warn about initialization of a char array with a too long constant C string.
diff --git a/symbol.c b/symbol.c
index 130071ab..97c2e35d 100644
--- a/symbol.c
+++ b/symbol.c
@@ -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)
+ 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;
diff --git a/symbol.h b/symbol.h
index 6d25e7fc..e1f53926 100644
--- a/symbol.h
+++ b/symbol.h
@@ -185,6 +185,7 @@ struct symbol {
examined:1,
expanding:1,
evaluated:1,
+ has_flex_array:1,
string:1,
designated_init:1,
forced_arg:1,
@@ -509,6 +510,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
+ */