All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.