[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <ilupya2l2yaseiokhgal65alkzbubylgz3nkdabqipi3xhbzxi@dkbofpqmuwdn>
Date: Mon, 4 Dec 2023 15:09:32 +0100
From: Luc Van Oostenryck <luc.vanoostenryck@...il.com>
To: Lukas Wunner <lukas@...ner.de>
Cc: Dan Carpenter <error27@...il.com>, oe-kbuild-all@...ts.linux.dev,
linux-kernel@...r.kernel.org, Bjorn Helgaas <helgaas@...nel.org>,
kernel test robot <lkp@...el.com>,
Mika Westerberg <mika.westerberg@...ux.intel.com>,
linux-sparse@...r.kernel.org
Subject: Re: drivers/pci/pcie/../pci.h:325:17: sparse: sparse: cast from
restricted pci_channel_state_t
On Sun, Dec 03, 2023 at 05:59:32PM +0100, Lukas Wunner wrote:
> Hi Dan,
>
> > > Please advise whether these sparse warnings are false positives which
> > > can be ignored and if they aren't, how to resolve them. If you happen
> > > to know the rationale for the cast, I'd be grateful if you could shed
> > > some light on it. Thanks a lot!
> >
> > The question is more why is pci_channel_state_t declared as __bit_wise.
> > __bit_wise data can only be used through accessor functions, like user
> > pointers have to go through copy_from_user() and endian data has to go
> > through le32_to_cpu() etc.
>
> __bitwise is not only to ensure endian correctness. It can be used to
> define data types which are integer-based, but treated as a distinct
> data type by sparse. A pci_channel_state_t value cannot be assigned
> to an integer variable of a different type, for example.
Correct. It was done on purpose to make a sort of 'strong' enum type,
and thus warn if pci_channel_state_t values are mixed with some other types.
> A few arches define arch_xchg() and arch_cmpxchg() as pure macros.
> The sparse warning for pci_channel_state_t does not appear on those
> arches. (These are: arc csky riscv x86)
>
> All other arches use a mix of macros and static inlines to define
> arch_xchg() and arch_cmpxchg(). The static inlines use unsigned long
> as argument and return types and the macros cast the argument type to
> unsigned long.
>
> Why are the casts necessary? Because there are callers of xchg() and
> cmpxchg() which pass pointers instead of integers as arguments.
Hmmm, I'm missing the precise context but it make me wonder what's happening
on 64-bit archs where enums are usually only 32-bit ...
> Examples include llist_del_all(), __wake_q_add(), mark_oom_victim(),
> fsnotify_attach_connector_to_object(). (Note that NULL is defined as
> "(void *)0".)
>
> When using xchg() or cmpxchg() with __bitwise arguments (as is done
> by commit 74ff8864cc84 in pci_dev_set_io_state()), the arches which
> define arch_xchg() and arch_cmpxchg() with static inlines see sparse
> warnings because the __bitwise arguments are cast to unsigned long.
> Those arches are: alpha arm arm64 hexagon loongarch m68k mips openrisc
> parisc powerpc s390 sh sparc xtensa
OK, if the underlying macros do as:
switch (size) {
case 1: ...
then things are ok there (but only if the size is given by a sizeof() of
the correct type (not casted to long or something).
> Indeed adding __force to the cast, as you suggest, should avoid the
> issue. sparse cannot parse the inline assembler, so it does not
> understand that arch_xchg() and arch_cmpxchg() internally perform a
> comparison and/or assignment. By adding __force, we therefore do not
> lose any validation coverage.
Yes, indeed, using __force inside specific accessors or any low-level macros,
like here these arch_xchg(), is OK. It's done in plenty of similar cases.
> A better approach might be to teach sparse that arch_xchg() and
> arch_cmpxchg() internally perform a comparison and/or assignment.
> Then sparse could validate the argument and return value types.
>
> builtin.c in the sparse source code already contains functions
> to handle __atomic_exchange() and __atomic_compare_exchange(),
> so I think xchg() and cmpxchg() should be handled there as well.
I don't agree. Sparse shouldn't know about the semantics of functions
in the kernel. Sparse offers some tools (annotations like the __bitwise,
noderef or address_space attributes for __user, __iomem, ... and type
checking stricter than standard/GCC C). By using these annotations, the
kernel can define a stricter semantic, that better suits its needs,
Sparse should know nothing about this, it's not its job.
Best regards,
-- Luc
Powered by blists - more mailing lists