All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: Ionela Voinescu <ionela.voinescu@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>,
	kernel test robot <lkp@intel.com>,
	kbuild-all@lists.01.org, linux-kernel@vger.kernel.org,
	Sudeep Holla <sudeep.holla@arm.com>
Subject: Re: arch/arm64/kernel/topology.c:367:22: sparse: sparse: dereference of noderef expression
Date: Wed, 6 Jan 2021 17:47:58 +0000	[thread overview]
Message-ID: <20210106174758.GD3579531@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20210106150724.GA16591@arm.com>

On Wed, Jan 06, 2021 at 03:07:24PM +0000, Ionela Voinescu wrote:

> > >  > 367		switch ((u64)reg->address) {
> > 
> > That's not a dereference but I guess sparse complains of dropping the
> > __iomem. We could change the cast to (__force u64) to silence sparse.

Oh, yes, it is - that of &reg->address, to fetch the value you are
casting to u64.  And nonsense in declaration of struct cpc_reg says
that its 'address' field somehow manages to be located in iomem,
regardless of where the entire structure is stored.

Qualifiers apply to lvalues - it's "how can that object be accessed".
They don't say anything with the values _stored_ in that object.
It is possible to have them applied to individual fields of a structure;
for some qualifiers that might be legitimate - e.g. you could do
struct foo {
	char *s;
	volatile int x;
} *p;
telling the compiler that p->x is to be treated as volatile (make no
assumptions about the value not being changed behind your back, etc.),
while p->s is not.

However, for __iomem (or __user, etc.) that makes no sense whatsoever;
you are saying "this field lives in iomem, no matter where the entire
structure is located".

To quote C99 6.3.2.1[2]:
	Except when it is the operand of the sizeof operator, the unary & operator, the ++
operator, the -- operator, or the left operand of the . operator or an assignment operator,
an lvalue that does not have array type is converted to the value stored in the designated
object (and is no longer an lvalue). If the lvalue has qualified type, the value has the
unqualified version of the type of the lvalue; otherwise, the value has the type of the
lvalue. If the lvalue has an incomplete type and does not have array type, the behavior is
undefined.

	IOW, in the example above, as lvalue p->x will have "volatile int"
for type; using it as argument of cast operator will convert it (_before_
doing the cast) to whatever integer that had been found stored
in that field and the type of that will be "int", not "volatile int".
As soon as you fetch the value stored in object, qualifiers are gone.

	The syntax is somewhat unfortunate - it's easy to confuse
qualified pointer to type with pointer to qualified type.
	const int *r
means "r is an unqualified pointer to const int"; the value stored in r may
be modified, but the value stored in *r may not.
	int * const r
means "r is a const pointer to int"; the value stored in r may not be modified,
but the value stored in *r may.

	You often run into something like
struct foo {
	...
	u64 __iomem *some_reg;
	...
} *p;
and, unlike the mess in struct cpc_reg declaration, here p->some_reg is *NOT*
__iomem-qualified.  It's a perfectly normal field of a structure somewhere
in kernel memory, it can be fetched from, stored into, etc.  The contents
of that field is a pointer to __iomem u64.  It can be passed to e.g.
readq(), but trying to directly fetch *(p->some_reg) will barf.
	In such cases the limitations apply not to how we can access the
field itself, but to what we can do with the value we find in that
field.

	At a guess, the intent of that (mis)annotation had been
"this field contains a 64bit unsigned integer that happens to contain
an address of something in iomem".  But qualifiers are useless for
that - once you've fetched that value, all you have is plain u64.
Nor would they be carried through the arithmetics, etc.

	It might be possible to cook something more useful by a bit
of creative misuse of __bitwise, but I hadn't looked through the
places where that field is used.

WARNING: multiple messages have this Message-ID (diff)
From: Al Viro <viro@zeniv.linux.org.uk>
To: kbuild-all@lists.01.org
Subject: Re: arch/arm64/kernel/topology.c:367:22: sparse: sparse: dereference of noderef expression
Date: Wed, 06 Jan 2021 17:47:58 +0000	[thread overview]
Message-ID: <20210106174758.GD3579531@ZenIV.linux.org.uk> (raw)
In-Reply-To: <20210106150724.GA16591@arm.com>

[-- Attachment #1: Type: text/plain, Size: 3601 bytes --]

On Wed, Jan 06, 2021 at 03:07:24PM +0000, Ionela Voinescu wrote:

> > >  > 367		switch ((u64)reg->address) {
> > 
> > That's not a dereference but I guess sparse complains of dropping the
> > __iomem. We could change the cast to (__force u64) to silence sparse.

Oh, yes, it is - that of &reg->address, to fetch the value you are
casting to u64.  And nonsense in declaration of struct cpc_reg says
that its 'address' field somehow manages to be located in iomem,
regardless of where the entire structure is stored.

Qualifiers apply to lvalues - it's "how can that object be accessed".
They don't say anything with the values _stored_ in that object.
It is possible to have them applied to individual fields of a structure;
for some qualifiers that might be legitimate - e.g. you could do
struct foo {
	char *s;
	volatile int x;
} *p;
telling the compiler that p->x is to be treated as volatile (make no
assumptions about the value not being changed behind your back, etc.),
while p->s is not.

However, for __iomem (or __user, etc.) that makes no sense whatsoever;
you are saying "this field lives in iomem, no matter where the entire
structure is located".

To quote C99 6.3.2.1[2]:
	Except when it is the operand of the sizeof operator, the unary & operator, the ++
operator, the -- operator, or the left operand of the . operator or an assignment operator,
an lvalue that does not have array type is converted to the value stored in the designated
object (and is no longer an lvalue). If the lvalue has qualified type, the value has the
unqualified version of the type of the lvalue; otherwise, the value has the type of the
lvalue. If the lvalue has an incomplete type and does not have array type, the behavior is
undefined.

	IOW, in the example above, as lvalue p->x will have "volatile int"
for type; using it as argument of cast operator will convert it (_before_
doing the cast) to whatever integer that had been found stored
in that field and the type of that will be "int", not "volatile int".
As soon as you fetch the value stored in object, qualifiers are gone.

	The syntax is somewhat unfortunate - it's easy to confuse
qualified pointer to type with pointer to qualified type.
	const int *r
means "r is an unqualified pointer to const int"; the value stored in r may
be modified, but the value stored in *r may not.
	int * const r
means "r is a const pointer to int"; the value stored in r may not be modified,
but the value stored in *r may.

	You often run into something like
struct foo {
	...
	u64 __iomem *some_reg;
	...
} *p;
and, unlike the mess in struct cpc_reg declaration, here p->some_reg is *NOT*
__iomem-qualified.  It's a perfectly normal field of a structure somewhere
in kernel memory, it can be fetched from, stored into, etc.  The contents
of that field is a pointer to __iomem u64.  It can be passed to e.g.
readq(), but trying to directly fetch *(p->some_reg) will barf.
	In such cases the limitations apply not to how we can access the
field itself, but to what we can do with the value we find in that
field.

	At a guess, the intent of that (mis)annotation had been
"this field contains a 64bit unsigned integer that happens to contain
an address of something in iomem".  But qualifiers are useless for
that - once you've fetched that value, all you have is plain u64.
Nor would they be carried through the arithmetics, etc.

	It might be possible to cook something more useful by a bit
of creative misuse of __bitwise, but I hadn't looked through the
places where that field is used.

  parent reply	other threads:[~2021-01-06 17:48 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-17 21:00 arch/arm64/kernel/topology.c:367:22: sparse: sparse: dereference of noderef expression kernel test robot
2020-12-17 21:00 ` kernel test robot
2020-12-18 10:44 ` Catalin Marinas
2020-12-18 10:44   ` Catalin Marinas
2021-01-06 15:07   ` Ionela Voinescu
2021-01-06 15:07     ` Ionela Voinescu
2021-01-06 15:21     ` Catalin Marinas
2021-01-06 15:21       ` Catalin Marinas
2021-01-06 15:52       ` Ionela Voinescu
2021-01-06 15:52         ` Ionela Voinescu
2021-01-06 16:13         ` Al Viro
2021-01-06 16:13           ` Al Viro
2021-01-06 16:47           ` Ionela Voinescu
2021-01-06 16:47             ` Ionela Voinescu
2021-01-06 17:47     ` Al Viro [this message]
2021-01-06 17:47       ` Al Viro
2021-01-06 20:12       ` Ionela Voinescu
2021-01-06 20:12         ` Ionela Voinescu
2021-01-06 20:46         ` Al Viro
2021-01-06 20:46           ` Al Viro
2021-01-06  5:50 kernel test robot
2021-01-06  5:50 ` kernel test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210106174758.GD3579531@ZenIV.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=catalin.marinas@arm.com \
    --cc=ionela.voinescu@arm.com \
    --cc=kbuild-all@lists.01.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lkp@intel.com \
    --cc=sudeep.holla@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.