All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] bogus cast in bio.c
@ 2005-09-09 15:53 viro
  2005-09-09 16:18 ` Andreas Schwab
  0 siblings, 1 reply; 8+ messages in thread
From: viro @ 2005-09-09 15:53 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

<qualifier> void * is not the same as void <qualifier> *...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
----
diff -urN RC13-git8-base/fs/bio.c current/fs/bio.c
--- RC13-git8-base/fs/bio.c	2005-09-08 10:17:39.000000000 -0400
+++ current/fs/bio.c	2005-09-08 23:53:33.000000000 -0400
@@ -683,7 +683,7 @@
 {
 	struct sg_iovec iov;
 
-	iov.iov_base = (__user void *)uaddr;
+	iov.iov_base = (void __user *)uaddr;
 	iov.iov_len = len;
 
 	return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm);

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

* Re: [PATCH] bogus cast in bio.c
  2005-09-09 15:53 [PATCH] bogus cast in bio.c viro
@ 2005-09-09 16:18 ` Andreas Schwab
  2005-09-09 16:36   ` viro
  0 siblings, 1 reply; 8+ messages in thread
From: Andreas Schwab @ 2005-09-09 16:18 UTC (permalink / raw)
  To: viro; +Cc: Linus Torvalds, linux-kernel

viro@ZenIV.linux.org.uk writes:

> <qualifier> void * is not the same as void <qualifier> *...

IMHO it should.

Andreas.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

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

* Re: [PATCH] bogus cast in bio.c
  2005-09-09 16:18 ` Andreas Schwab
@ 2005-09-09 16:36   ` viro
  2005-09-09 17:29     ` [sparse fix] (was Re: [PATCH] bogus cast in bio.c) viro
  0 siblings, 1 reply; 8+ messages in thread
From: viro @ 2005-09-09 16:36 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Linus Torvalds, linux-kernel

On Fri, Sep 09, 2005 at 06:18:14PM +0200, Andreas Schwab wrote:
> viro@ZenIV.linux.org.uk writes:
> 
> > <qualifier> void * is not the same as void <qualifier> *...
> 
> IMHO it should.

... and indeed it should.  My apologies - that's a combination of
sparse bug and me being very low on coffee...

FWIW, looks like we are losing address_space in the first form: with current
sparse we get
fs/bio.c:686:15: warning: incorrect type in assignment (different address spaces)
fs/bio.c:686:15:    expected void [noderef] *iov_base<asn:1>
fs/bio.c:686:15:    got void [noderef] *<noident>
from the first form (cast to __user void *).  Lovely...

OK, I think I know what's going on there, will fix.

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

* [sparse fix] (was Re: [PATCH] bogus cast in bio.c)
  2005-09-09 16:36   ` viro
@ 2005-09-09 17:29     ` viro
  2005-09-09 17:34       ` viro
  2005-09-09 17:48       ` Linus Torvalds
  0 siblings, 2 replies; 8+ messages in thread
From: viro @ 2005-09-09 17:29 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Andreas Schwab, linux-kernel

> fs/bio.c:686:15: warning: incorrect type in assignment (different address spaces)
> fs/bio.c:686:15:    expected void [noderef] *iov_base<asn:1>
> fs/bio.c:686:15:    got void [noderef] *<noident>
> from the first form (cast to __user void *).  Lovely...
> 
> OK, I think I know what's going on there, will fix.

What happens is actually pretty simple - we get address_space(1) handled
in declaration_specifiers(), which sets ctype->as to 1.  Then we see
"void" and eventually get to
                        ctype->base_type = type;
                }

                check_modifiers(&token->pos, s, ctype->modifiers);
                apply_ctype(token->pos, &thistype, ctype);
with thistype coming from lookup for "void".  And that, of course, has
zero ->as.  Now apply_ctype merrily buggers ctype->as and we have 0...

So AFAICS proper fix for sparse should be to check thistype->as to see
if it really has any intention to change ->as.  ACK?

--- parse.c	2005-09-07 17:03:13.000000000 -0400
+++ parse.c.new	2005-09-09 13:25:01.000000000 -0400
@@ -636,7 +636,8 @@
 		ctype->alignment = thistype->alignment;
 
 	/* Address space */
-	ctype->as = thistype->as;
+	if (thistype->as)
+		ctype->as = thistype->as;
 }
 
 static void check_modifiers(struct position *pos, struct symbol *s, unsigned long mod)

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

* Re: [sparse fix] (was Re: [PATCH] bogus cast in bio.c)
  2005-09-09 17:29     ` [sparse fix] (was Re: [PATCH] bogus cast in bio.c) viro
@ 2005-09-09 17:34       ` viro
  2005-09-09 17:48       ` Linus Torvalds
  1 sibling, 0 replies; 8+ messages in thread
From: viro @ 2005-09-09 17:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Andreas Schwab, linux-kernel

On Fri, Sep 09, 2005 at 06:29:38PM +0100, viro@ZenIV.linux.org.uk wrote:
> > fs/bio.c:686:15: warning: incorrect type in assignment (different address spaces)
> > fs/bio.c:686:15:    expected void [noderef] *iov_base<asn:1>
> > fs/bio.c:686:15:    got void [noderef] *<noident>
> > from the first form (cast to __user void *).  Lovely...
> > 
> > OK, I think I know what's going on there, will fix.
> 
> What happens is actually pretty simple - we get address_space(1) handled
> in declaration_specifiers(), which sets ctype->as to 1.  Then we see
> "void" and eventually get to
>                         ctype->base_type = type;
>                 }
> 
>                 check_modifiers(&token->pos, s, ctype->modifiers);
>                 apply_ctype(token->pos, &thistype, ctype);
> with thistype coming from lookup for "void".  And that, of course, has
> zero ->as.  Now apply_ctype merrily buggers ctype->as and we have 0...
> 
> So AFAICS proper fix for sparse should be to check thistype->as to see
> if it really has any intention to change ->as.  ACK?

PS: obvious testcase for that one:

#define X __attribute__((address_space(1)))    
void X *p;
void X *q;
void foo(unsigned long n)
{
        p = (void X *)n;
        q = (X void *)n;
}

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

* Re: [sparse fix] (was Re: [PATCH] bogus cast in bio.c)
  2005-09-09 17:29     ` [sparse fix] (was Re: [PATCH] bogus cast in bio.c) viro
  2005-09-09 17:34       ` viro
@ 2005-09-09 17:48       ` Linus Torvalds
  2005-09-09 18:15         ` Linus Torvalds
  1 sibling, 1 reply; 8+ messages in thread
From: Linus Torvalds @ 2005-09-09 17:48 UTC (permalink / raw)
  To: viro; +Cc: Andreas Schwab, linux-kernel



On Fri, 9 Sep 2005 viro@ZenIV.linux.org.uk wrote:
> 
> So AFAICS proper fix for sparse should be to check thistype->as to see
> if it really has any intention to change ->as.  ACK?

Ack. Applied,

		Linus

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

* Re: [sparse fix] (was Re: [PATCH] bogus cast in bio.c)
  2005-09-09 17:48       ` Linus Torvalds
@ 2005-09-09 18:15         ` Linus Torvalds
  2005-09-09 20:10           ` viro
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Torvalds @ 2005-09-09 18:15 UTC (permalink / raw)
  To: viro; +Cc: Andreas Schwab, linux-kernel



On Fri, 9 Sep 2005, Linus Torvalds wrote:
> 
> Ack. Applied,

Btw, I also just committed the fix to not warn for

	#if defined(TOKEN) && TOKEN > 1

when TOKEN is undefined and -Wundef is enabled. Implemented exactly the
way you suggested.

		Linus

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

* Re: [sparse fix] (was Re: [PATCH] bogus cast in bio.c)
  2005-09-09 18:15         ` Linus Torvalds
@ 2005-09-09 20:10           ` viro
  0 siblings, 0 replies; 8+ messages in thread
From: viro @ 2005-09-09 20:10 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Andreas Schwab, linux-kernel

On Fri, Sep 09, 2005 at 11:15:41AM -0700, Linus Torvalds wrote:
> 
> 
> On Fri, 9 Sep 2005, Linus Torvalds wrote:
> > 
> > Ack. Applied,
> 
> Btw, I also just committed the fix to not warn for
> 
> 	#if defined(TOKEN) && TOKEN > 1
> 
> when TOKEN is undefined and -Wundef is enabled. Implemented exactly the
> way you suggested.

Cool...  Speaking of sparse patches:

* generates a warning when we cast _between_ address spaces (e.g. cast from
__user to __iomem).
* optional (on -Wcast-to-as) warning when casting _TO_ address space (e.g.
when normal pointer is cast to __iomem one - that caught a lot of crap in
drivers).  casts from unsigned long are still OK, so's cast from 0, so's
__force cast, of course.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
----
diff --git a/evaluate.c b/evaluate.c
--- a/evaluate.c
+++ b/evaluate.c
@@ -2049,11 +2049,27 @@ static int get_as(struct symbol *sym)
 	return as;
 }
 
+static void cast_to_as(struct expression *e, int as)
+{
+	struct expression *v = e->cast_expression;
+
+	if (!Wcast_to_address_space)
+		return;
+
+	/* cast from constant 0 to pointer is OK */
+	if (v->type == EXPR_VALUE && is_int_type(v->ctype) && !v->value)
+		return;
+
+	warning(e->pos, "cast adds address space to expression (<asn:%d>)", as);
+}
+
 static struct symbol *evaluate_cast(struct expression *expr)
 {
 	struct expression *target = expr->cast_expression;
 	struct symbol *ctype = examine_symbol_type(expr->cast_type);
-	enum type type;
+	struct symbol *t1, *t2;
+	enum type type1, type2;
+	int as1, as2;
 
 	if (!target)
 		return NULL;
@@ -2092,51 +2108,54 @@ static struct symbol *evaluate_cast(stru
 	evaluate_expression(target);
 	degenerate(target);
 
+	t1 = ctype;
+	if (t1->type == SYM_NODE)
+		t1 = t1->ctype.base_type;
+	if (t1->type == SYM_ENUM)
+		t1 = t1->ctype.base_type;
+
 	/*
 	 * You can always throw a value away by casting to
 	 * "void" - that's an implicit "force". Note that
 	 * the same is _not_ true of "void *".
 	 */
-	if (ctype == &void_ctype)
+	if (t1 == &void_ctype)
 		goto out;
 
-	type = ctype->type;
-	if (type == SYM_NODE) {
-		type = ctype->ctype.base_type->type;
-		if (ctype->ctype.base_type == &void_ctype)
-			goto out;
-	}
-	if (type == SYM_ARRAY || type == SYM_UNION || type == SYM_STRUCT)
+	type1 = t1->type;
+	if (type1 == SYM_ARRAY || type1 == SYM_UNION || type1 == SYM_STRUCT)
 		warning(expr->pos, "cast to non-scalar");
 
-	if (!target->ctype) {
+	t2 = target->ctype;
+	if (!t2) {
 		warning(expr->pos, "cast from unknown type");
 		goto out;
 	}
+	if (t2->type == SYM_NODE)
+		t2 = t2->ctype.base_type;
+	if (t2->type == SYM_ENUM)
+		t2 = t2->ctype.base_type;
 
-	type = target->ctype->type;
-	if (type == SYM_NODE)
-		type = target->ctype->ctype.base_type->type;
-	if (type == SYM_ARRAY || type == SYM_UNION || type == SYM_STRUCT)
+	type2 = t2->type;
+	if (type2 == SYM_ARRAY || type2 == SYM_UNION || type2 == SYM_STRUCT)
 		warning(expr->pos, "cast from non-scalar");
 
-	if (!get_as(ctype) && get_as(target->ctype) > 0)
-		warning(expr->pos, "cast removes address space of expression");
-
-	if (!(ctype->ctype.modifiers & MOD_FORCE)) {
-		struct symbol *t1 = ctype, *t2 = target->ctype;
-		if (t1->type == SYM_NODE)
-			t1 = t1->ctype.base_type;
-		if (t2->type == SYM_NODE)
-			t2 = t2->ctype.base_type;
-		if (t1 != t2) {
-			if (t1->type == SYM_RESTRICT)
-				warning(expr->pos, "cast to restricted type");
-			if (t2->type == SYM_RESTRICT)
-				warning(expr->pos, "cast from restricted type");
-		}
+	if (!(ctype->ctype.modifiers & MOD_FORCE) && t1 != t2) {
+		if (t1->type == SYM_RESTRICT)
+			warning(expr->pos, "cast to restricted type");
+		if (t2->type == SYM_RESTRICT)
+			warning(expr->pos, "cast from restricted type");
 	}
 
+	as1 = get_as(ctype);
+	as2 = get_as(target->ctype);
+	if (!as1 && as2 > 0)
+		warning(expr->pos, "cast removes address space of expression");
+	if (as1 > 0 && as2 > 0 && as1 != as2)
+		warning(expr->pos, "cast between address spaces (<asn:%d>-><asn:%d>)", as2, as1);
+	if (as1 > 0 && !as2)
+		cast_to_as(expr, as1);
+
 	/*
 	 * Casts of constant values are special: they
 	 * can be NULL, and thus need to be simplified
diff --git a/lib.c b/lib.c
--- a/lib.c
+++ b/lib.c
@@ -170,6 +170,7 @@ int Wtypesign = 0;
 int Wcontext = 0;
 int Wundefined_preprocessor = 0;
 int Wptr_subtraction_blows = 0;
+int Wcast_to_address_space = 0;
 int Wtransparent_union = 1;
 int preprocess_only;
 char *include;
@@ -295,6 +296,7 @@ static const struct warning {
 	const char *name;
 	int *flag;
 } warnings[] = {
+	{ "cast-to-as", &Wcast_to_address_space },
 	{ "ptr-subtraction-blows", &Wptr_subtraction_blows },
 	{ "default-bitfield-sign", &Wdefault_bitfield_sign },
 	{ "undef", &Wundefined_preprocessor },
diff --git a/lib.h b/lib.h
--- a/lib.h
+++ b/lib.h
@@ -79,6 +79,7 @@ extern int Wdefault_bitfield_sign;
 extern int Wundefined_preprocessor;
 extern int Wbitwise, Wtypesign, Wcontext;
 extern int Wtransparent_union;
+extern int Wcast_to_address_space;
 
 extern void declare_builtin_functions(void);
 extern void create_builtin_stream(void);

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

end of thread, other threads:[~2005-09-09 20:10 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-09 15:53 [PATCH] bogus cast in bio.c viro
2005-09-09 16:18 ` Andreas Schwab
2005-09-09 16:36   ` viro
2005-09-09 17:29     ` [sparse fix] (was Re: [PATCH] bogus cast in bio.c) viro
2005-09-09 17:34       ` viro
2005-09-09 17:48       ` Linus Torvalds
2005-09-09 18:15         ` Linus Torvalds
2005-09-09 20:10           ` viro

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.