linux-sparse.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] teach sparse about union casts
@ 2020-08-15 15:28 Luc Van Oostenryck
  2020-08-15 15:28 ` [PATCH 1/3] union-cast: add some testcases Luc Van Oostenryck
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2020-08-15 15:28 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

This series adds support for union casts which otherwise give
technically exact diagnostic messages:
	warning: cast to non-scalar
But these warnings are not interesting because GCC and clang
support these casts, they are used in the kernel (but not much:
~13 in the usual x86 configs) and they are not especially dangerous
(like losing bits or cheating with types).


Luc Van Oostenryck (3):
  union-cast: add some testcases
  union-cast: extract evaluate_compound_literal()
  union-cast: teach sparse about union casts

 Documentation/release-notes/v0.6.3.rst |  5 ++
 evaluate.c                             | 88 ++++++++++++++++++++------
 options.c                              |  2 +
 options.h                              |  1 +
 sparse.1                               |  6 ++
 validation/eval/union-cast-no.c        | 23 +++++++
 validation/eval/union-cast.c           | 24 +++++++
 7 files changed, 129 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/release-notes/v0.6.3.rst
 create mode 100644 validation/eval/union-cast-no.c
 create mode 100644 validation/eval/union-cast.c


base-commit: 49f7e13a7ac9a582d11e9c1ad01e71740f486601
-- 
2.28.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] union-cast: add some testcases
  2020-08-15 15:28 [PATCH 0/3] teach sparse about union casts Luc Van Oostenryck
@ 2020-08-15 15:28 ` Luc Van Oostenryck
  2020-08-15 15:28 ` [PATCH 2/3] union-cast: extract evaluate_compound_literal() Luc Van Oostenryck
  2020-08-15 15:28 ` [PATCH 3/3] union-cast: teach sparse about union casts Luc Van Oostenryck
  2 siblings, 0 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2020-08-15 15:28 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

Casts to union type are a GCC extension and are similar to
compound literals.

However, sparse doesn't know about them and treats them like
other casts to non-scalars.

Add some testcases for this and its upcoming warning flag.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 validation/eval/union-cast-no.c | 24 ++++++++++++++++++++++++
 validation/eval/union-cast.c    | 25 +++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/validation/eval/union-cast-no.c b/validation/eval/union-cast-no.c
new file mode 100644
index 000000000000..d06b348d209e
--- /dev/null
+++ b/validation/eval/union-cast-no.c
@@ -0,0 +1,24 @@
+union u {
+	int	i;
+	char	x[8];
+};
+
+static union u foo(int i)
+{
+	return (union u)i;
+}
+
+static union u bar(long l)
+{
+	return (union u)l;
+}
+
+/*
+ * check-name: union-cast-no
+ * check-command: sparse -Wno-union-cast $file
+ * check-known-to-fail
+ *
+ * check-error-start
+eval/union-cast-no.c:13:17: warning: cast to non-scalar
+ * check-error-end
+ */
diff --git a/validation/eval/union-cast.c b/validation/eval/union-cast.c
new file mode 100644
index 000000000000..1d8167531081
--- /dev/null
+++ b/validation/eval/union-cast.c
@@ -0,0 +1,25 @@
+union u {
+	int	i;
+	char	x[8];
+};
+
+static union u foo(int a)
+{
+	return (union u)a;
+}
+
+static union u bar(long a)
+{
+	return (union u)a;
+}
+
+/*
+ * check-name: union-cast
+ * check-command: sparse -Wunion-cast $file
+ * check-known-to-fail
+ *
+ * check-error-start
+eval/union-cast.c:8:17: warning: cast to union type
+eval/union-cast.c:13:17: warning: cast to non-scalar
+ * check-error-end
+ */
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] union-cast: extract evaluate_compound_literal()
  2020-08-15 15:28 [PATCH 0/3] teach sparse about union casts Luc Van Oostenryck
  2020-08-15 15:28 ` [PATCH 1/3] union-cast: add some testcases Luc Van Oostenryck
@ 2020-08-15 15:28 ` Luc Van Oostenryck
  2020-08-15 15:28 ` [PATCH 3/3] union-cast: teach sparse about union casts Luc Van Oostenryck
  2 siblings, 0 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2020-08-15 15:28 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

extract evaluate_compound_literal() from evaluate_cast,
in preparation for supporting union casts.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 evaluate.c | 41 ++++++++++++++++++++++-------------------
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/evaluate.c b/evaluate.c
index 63a9390b5ee7..0563be939f23 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2948,6 +2948,26 @@ static int cast_flags(struct expression *expr, struct expression *old)
 	return flags;
 }
 
+static struct symbol *evaluate_compound_literal(struct expression *expr, struct expression *source)
+{
+	struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
+	struct symbol *sym = expr->cast_type;
+
+	sym->initializer = source;
+	evaluate_symbol(sym);
+
+	addr->ctype = &lazy_ptr_ctype;	/* Lazy eval */
+	addr->symbol = sym;
+	if (sym->ctype.modifiers & MOD_TOPLEVEL)
+		addr->flags |= CEF_ADDR;
+
+	expr->type = EXPR_PREOP;
+	expr->op = '*';
+	expr->deref = addr;
+	expr->ctype = sym;
+	return sym;
+}
+
 static struct symbol *evaluate_cast(struct expression *expr)
 {
 	struct expression *source = expr->cast_expression;
@@ -2970,25 +2990,8 @@ static struct symbol *evaluate_cast(struct expression *expr)
 	 * dereferenced as part of a post-fix expression.
 	 * We need to produce an expression that can be dereferenced.
 	 */
-	if (source->type == EXPR_INITIALIZER) {
-		struct symbol *sym = expr->cast_type;
-		struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
-
-		sym->initializer = source;
-		evaluate_symbol(sym);
-
-		addr->ctype = &lazy_ptr_ctype;	/* Lazy eval */
-		addr->symbol = sym;
-		if (sym->ctype.modifiers & MOD_TOPLEVEL)
-			addr->flags |= CEF_ADDR;
-
-		expr->type = EXPR_PREOP;
-		expr->op = '*';
-		expr->unop = addr;
-		expr->ctype = sym;
-
-		return sym;
-	}
+	if (source->type == EXPR_INITIALIZER)
+		return evaluate_compound_literal(expr, source);
 
 	ctype = examine_symbol_type(expr->cast_type);
 	expr->ctype = ctype;
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] union-cast: teach sparse about union casts
  2020-08-15 15:28 [PATCH 0/3] teach sparse about union casts Luc Van Oostenryck
  2020-08-15 15:28 ` [PATCH 1/3] union-cast: add some testcases Luc Van Oostenryck
  2020-08-15 15:28 ` [PATCH 2/3] union-cast: extract evaluate_compound_literal() Luc Van Oostenryck
@ 2020-08-15 15:28 ` Luc Van Oostenryck
  2 siblings, 0 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2020-08-15 15:28 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

Casts to union type are a GCC extension and are similar to
compound literals.

However, sparse doesn't know about them and treats them like
other casts to non-scalars.

So, teach sparse about them, convert them to the corresponding
compound literal and add a warning flag to enable/disable the
associated warning: -W[no-]union-cast.

Note: a difference between union casts and compound literals
      is that the union casts yield rvalues while compound
      literals are lvalues but this distinction is not yet done
      in this series.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 Documentation/release-notes/v0.6.3.rst |  5 +++
 evaluate.c                             | 47 +++++++++++++++++++++++++-
 options.c                              |  2 ++
 options.h                              |  1 +
 sparse.1                               |  6 ++++
 validation/eval/union-cast-no.c        |  1 -
 validation/eval/union-cast.c           |  1 -
 7 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/Documentation/release-notes/v0.6.3.rst b/Documentation/release-notes/v0.6.3.rst
new file mode 100644
index 000000000000..1aae742e42de
--- /dev/null
+++ b/Documentation/release-notes/v0.6.3.rst
@@ -0,0 +1,5 @@
+v0.6.3 (2020-xx-xy)
+===================
+
+* Changes in warnings:
+    "warning: cast to union type" [disable with -Wno-union-cast]
diff --git a/evaluate.c b/evaluate.c
index 0563be939f23..847137250d05 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -2948,6 +2948,26 @@ static int cast_flags(struct expression *expr, struct expression *old)
 	return flags;
 }
 
+///
+// check if a type matches one of the members of a union type
+// @utype: the union type
+// @type: to type to check
+// @return: to identifier of the matching type in the union.
+static struct symbol *find_member_type(struct symbol *utype, struct symbol *type)
+{
+	struct symbol *t, *member;
+
+	if (utype->type != SYM_UNION)
+		return NULL;
+
+	FOR_EACH_PTR(utype->symbol_list, member) {
+		classify_type(member, &t);
+		if (type == t)
+			return member;
+	} END_FOR_EACH_PTR(member);
+	return NULL;
+}
+
 static struct symbol *evaluate_compound_literal(struct expression *expr, struct expression *source)
 {
 	struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL);
@@ -2973,6 +2993,7 @@ static struct symbol *evaluate_cast(struct expression *expr)
 	struct expression *source = expr->cast_expression;
 	struct symbol *ctype;
 	struct symbol *ttype, *stype;
+	struct symbol *member;
 	int tclass, sclass;
 	struct ident *tas = NULL, *sas = NULL;
 
@@ -3022,8 +3043,32 @@ static struct symbol *evaluate_cast(struct expression *expr)
 	if (expr->type == EXPR_FORCE_CAST)
 		goto out;
 
-	if (tclass & (TYPE_COMPOUND | TYPE_FN))
+	if (tclass & (TYPE_COMPOUND | TYPE_FN)) {
+		/*
+		 * Special case: cast to union type (GCC extension)
+		 * The effect is similar to a compound literal except
+		 * that the result is a rvalue.
+		 */
+		if ((member = find_member_type(ttype, stype))) {
+			struct expression *item, *init;
+
+			if (Wunion_cast)
+				warning(expr->pos, "cast to union type");
+
+			item = alloc_expression(source->pos, EXPR_IDENTIFIER);
+			item->expr_ident = member->ident;
+			item->ident_expression = source;
+
+			init = alloc_expression(source->pos, EXPR_INITIALIZER);
+			add_expression(&init->expr_list, item);
+
+			// FIXME: this should be a rvalue
+			evaluate_compound_literal(expr, init);
+			return ctype;
+		}
+
 		warning(expr->pos, "cast to non-scalar");
+	}
 
 	if (sclass & TYPE_COMPOUND)
 		warning(expr->pos, "cast from non-scalar");
diff --git a/options.c b/options.c
index f7e81b84d749..b25f715042f8 100644
--- a/options.c
+++ b/options.c
@@ -129,6 +129,7 @@ int Wtransparent_union = 0;
 int Wtypesign = 0;
 int Wundef = 0;
 int Wuninitialized = 1;
+int Wunion_cast = 0;
 int Wuniversal_initializer = 0;
 int Wunknown_attribute = 0;
 int Wvla = 1;
@@ -866,6 +867,7 @@ static const struct flag warnings[] = {
 	{ "typesign", &Wtypesign },
 	{ "undef", &Wundef },
 	{ "uninitialized", &Wuninitialized },
+	{ "union-cast", &Wunion_cast },
 	{ "universal-initializer", &Wuniversal_initializer },
 	{ "unknown-attribute", &Wunknown_attribute },
 	{ "vla", &Wvla },
diff --git a/options.h b/options.h
index 070c0dd87183..40945e287a4a 100644
--- a/options.h
+++ b/options.h
@@ -128,6 +128,7 @@ extern int Wtransparent_union;
 extern int Wtypesign;
 extern int Wundef;
 extern int Wuninitialized;
+extern int Wunion_cast;
 extern int Wuniversal_initializer;
 extern int Wunknown_attribute;
 extern int Wvla;
diff --git a/sparse.1 b/sparse.1
index 60203d5a6463..fecd6dd90d42 100644
--- a/sparse.1
+++ b/sparse.1
@@ -451,6 +451,12 @@ The concerned warnings are, for example, those triggered by
 Sparse does not issue these warnings by default, processing '{\ 0\ }'
 the same as '{\ }'.
 .
+.TP
+.B -Wunion-cast
+Warn on casts to union types.
+
+Sparse does not issues these warnings by default.
+.
 .SH MISC OPTIONS
 .TP
 .B \-\-arch=\fIARCH\fR
diff --git a/validation/eval/union-cast-no.c b/validation/eval/union-cast-no.c
index d06b348d209e..6ba38db8e3f3 100644
--- a/validation/eval/union-cast-no.c
+++ b/validation/eval/union-cast-no.c
@@ -16,7 +16,6 @@ static union u bar(long l)
 /*
  * check-name: union-cast-no
  * check-command: sparse -Wno-union-cast $file
- * check-known-to-fail
  *
  * check-error-start
 eval/union-cast-no.c:13:17: warning: cast to non-scalar
diff --git a/validation/eval/union-cast.c b/validation/eval/union-cast.c
index 1d8167531081..5bee9e0dc705 100644
--- a/validation/eval/union-cast.c
+++ b/validation/eval/union-cast.c
@@ -16,7 +16,6 @@ static union u bar(long a)
 /*
  * check-name: union-cast
  * check-command: sparse -Wunion-cast $file
- * check-known-to-fail
  *
  * check-error-start
 eval/union-cast.c:8:17: warning: cast to union type
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-08-15 22:02 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-15 15:28 [PATCH 0/3] teach sparse about union casts Luc Van Oostenryck
2020-08-15 15:28 ` [PATCH 1/3] union-cast: add some testcases Luc Van Oostenryck
2020-08-15 15:28 ` [PATCH 2/3] union-cast: extract evaluate_compound_literal() Luc Van Oostenryck
2020-08-15 15:28 ` [PATCH 3/3] union-cast: teach sparse about union casts Luc Van Oostenryck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).