All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ingo Molnar <mingo@kernel.org>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Chris Metcalf <cmetcalf@ezchip.com>,
	open list <linux-kernel@vger.kernel.org>,
	Peter Zijlstra <a.p.zijlstra@chello.nl>,
	Thomas Gleixner <tglx@linutronix.de>,
	"H. Peter Anvin" <hpa@zytor.com>, Borislav Petkov <bp@alien8.de>
Subject: Re: [PATCH] string: Improve the generic strlcpy() implementation
Date: Mon, 5 Oct 2015 16:04:43 +0200	[thread overview]
Message-ID: <20151005140443.GA5391@gmail.com> (raw)
In-Reply-To: <20151005131524.GA807@gmail.com>


* Ingo Molnar <mingo@kernel.org> wrote:

> Hm, so GCC (v4.9.2) will only warn about this bug if -Wtype-limits is enabled 
> explicitly:
> 
>  lib/string.c: In function ‘strlcpy’:
>  lib/string.c:228:32: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
>    if (unlikely((size_t)dst_size < 0)) {
>                                  ^
> 
> ... which we don't do in the kernel.
> 
> Has anyone considered enabling -Wtype-limits? It seems to catch real bugs.
> 
> I can see there are patches that enable -Wextra (which enables -Wtype-limits and 
> many other warnings), but it would be more manageable to just enable one such 
> warning at a time.

So I checked this and -Wtype-limits is super chatty at the moment, on various 
configs on x86:

 def64:    warnings:  51, delta: +51
 def32:    warnings:  50, delta: +50
 allno64:  warnings:  24, delta: +21
 allno32:  warnings:  26, delta: +24
 allyes64: warnings: 292, delta: +278
 allyes32: warnings: 318, delta: +277
 allmod64: warnings: 298, delta: +287
 allmod32: warnings: 324, delta: +286

(The delta column is the number of new warnings relative to v4.3-rc4.)

I picked 10 random warnings that triggered in files that looked interesting to me:

1) false positive warning:

./arch/x86/include/asm/apic.h:33:11: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]

is caused by macro substitution:

#define apic_printk(v, s, a...) do {       \
                if ((v) <= apic_verbosity) \
                        printk(s, ##a);    \
        } while (0)

so if 'v' is 0 GCC thinks it's a bad comparison - while it isn't.

This would be easily worked around if we moved the code from CPP to C - which is 
beneficial in any case.

2) confused code (possibly harmful):

arch/x86/kernel/pci-calgary_64.c:299:25: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]

this:

  static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, unsigned int npages)
  {

	...
        if (unlikely((dma_addr >= DMA_ERROR_CODE) && (dma_addr < badend))) {
                WARN(1, KERN_ERR "Calgary: driver tried unmapping bad DMA "
                       "address 0x%Lx\n", dma_addr);
                return;
        }

is nonsense because dma_addr is unsigned and DMA_ERROR_CODE is 0. The right way to 
check for DMA_ERROR_CODE is to check it:

  triton:~/tip> git grep DMA_ERROR_CODE | grep -E '==|!=' | wc -l
  29

not compare it:

  triton:~/tip> git grep DMA_ERROR_CODE | grep -E ' <= | >= | < | > ' | wc -l
  1

3) false positive warning:

block/cfq-iosched.c:4657:13: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

substition of '0' in the STORE_FUNCTION() macro causes this one.

4) confused code (looks harmless):

crypto/asymmetric_keys/x509_cert_parser.c:549:11: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

        unsigned year, mon, day, hour, min, sec, mon_len;
	...

            hour < 0 || hour > 23 ||

so 'hour' cannot be negative. Looks harmless.

5) false positive warning:

drivers/nvdimm/pmem.c:257:38: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

        if (nvdimm_namespace_capacity(ndns) < ND_PFN_ALIGN

so ND_PFN_ALIGN can be 0 if CONFIG_NVDIMM_PFN is disabled.

6) confused code (looks harmless):

kernel/auditsc.c:1027:23: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

        size_t len, len_left, to_send;

	...

        if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {

So this looks like a real bug similar to the one I made in the strlcpy() warning: 
the code wants to warn about a negative underflow - but instead it does not check 
for that condition at all.

It's harmless because the len > MAX_ARG_STRLEN-1 check would catch any underflows.

7) confused code (looks harmless):

mm/memblock.c:840:11: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]


	void __init_memblock __next_reserved_mem_region(u64 *idx,
	...

        if (*idx >= 0 && *idx < type->cnt) {

so *idx is u64 so it's always >= 0. Looks harmless.

8) confused code (looks harmless):

fs/cachefiles/bind.c:42:30: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]

        /* start by checking things over */
        ASSERT(cache->fstop_percent >= 0 &&
               cache->fstop_percent < cache->fcull_percent &&
               cache->fcull_percent < cache->frun_percent &&
               cache->frun_percent  < 100);


'fstop_percent' is unsigned int, so the >= 0 test is superfluous. Looks harmless.

9) confused code (looks harmless):

fs/cachefiles/daemon.c:225:14: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

                                       size_t datalen,
	...

        if (datalen < 0 || datalen > PAGE_SIZE - 1)
                return -EOPNOTSUPP;


so 'datalen' is unsigned and this can never be negative - and the second check 
catches any underflows. Looks harmless.

10) somewhat confused code (harmless):

net/rds/iw_recv.c:203:26: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

So this comes from the comparison of RDS_PAGE_LAST_OFF:

        get_page(recv->r_frag->f_page);

        if (ic->i_frag.f_offset < RDS_PAGE_LAST_OFF) {
                ic->i_frag.f_offset += RDS_FRAG_SIZE;
        } else {
                put_page(ic->i_frag.f_page);
                ic->i_frag.f_page = NULL;
                ic->i_frag.f_offset = 0;
        }

but i_frag.f_offset is unsigned:

 net/rds/iw.h:   unsigned long           f_offset;

and:

 net/rds/iw.h:#define RDS_PAGE_LAST_OFF (((PAGE_SIZE  / RDS_FRAG_SIZE) - 1) * RDS_FRAG_SIZE)

where RDS_FRAG_SIZE == 4096, so RDS_PAGE_LAST_OFF becomes 0.

if RDS_FRAG_SIZE was smaller than 4096, say 512, then RDS_PAGE_LAST_OFF would show 
the offset within the page of the last fragment, i.e. 3584.

So the code looks correct but inefficient: it does the get_page()/put_page() 
unnecessarily in the RDS_FRAG_SIZE == PAGE_SIZE case, which is the default on most 
architectures.

I'd write this as:

        if (ic->i_frag.f_offset < RDS_PAGE_LAST_OFF) {
	        get_page(recv->r_frag->f_page);
                ic->i_frag.f_offset += RDS_FRAG_SIZE;
        } else {
                ic->i_frag.f_page = NULL;
                ic->i_frag.f_offset = 0;
        }

(but this would still generate the warning.)

============

So the summary from 10 examples is:

 1) false positive warning
 2) confused code (possibly harmful)
 3) false positive warning
 4) confused code (looks harmless)
 5) false positive warning
 6) confused code (looks harmless)
 7) confused code (looks harmless)
 8) confused code (looks harmless)
 9) confused code (looks harmless)
10) somewhat confused code (harmless)

I.e. 3 genuine false positive warnings, 6 pointing out harmless looking code 
confusion, 1 pointing out harmful looking code confusion - and one of the sites it 
pointed out highlighted an inefficiency.

That doesn't look too bad of a false positive ration from a compiler warning, 
especially considering that static checkers (and people running -Wextra builds) 
have been cleaning out these cases for quite some time it appears, which means 
these are the leftover warnings.

Thanks,

	Ingo

  reply	other threads:[~2015-10-05 14:04 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-10 19:43 [GIT PULL] strscpy string copy function Chris Metcalf
2015-10-04 15:55 ` Linus Torvalds
2015-10-05 11:27   ` [PATCH] string: Improve the generic strlcpy() implementation Ingo Molnar
2015-10-05 11:53     ` Ingo Molnar
2015-10-05 13:15       ` Ingo Molnar
2015-10-05 14:04         ` Ingo Molnar [this message]
     [not found]         ` <CA+55aFx2McOeEiB7fJ-BV=vBsH=i2cC-qW8_EBEnScfQhugD_w@mail.gmail.com>
2015-10-05 14:07           ` Ingo Molnar
2015-10-05 14:33           ` Ingo Molnar
2015-10-05 15:32             ` Linus Torvalds
2015-10-05 16:03               ` Ingo Molnar
2015-10-05 12:28     ` Linus Torvalds
2015-10-05 13:10       ` Ingo Molnar
2015-10-05 22:28     ` Rasmus Villemoes
2015-10-06  7:54       ` Ingo Molnar
2015-10-06  8:03       ` Ingo Molnar
2015-10-06 22:00         ` Rasmus Villemoes
2015-10-07  7:18           ` Ingo Molnar
2015-10-07  9:04             ` Rasmus Villemoes
2015-10-07  9:22               ` Linus Torvalds
2015-10-08  8:48                 ` Ingo Molnar
2015-10-09  8:10                   ` Rasmus Villemoes
2015-10-09  9:10                     ` [RFC 0/3] eliminate potential race in string() (was: [PATCH] string: Improve the generic strlcpy() implementation) Rasmus Villemoes
2015-10-09  9:14                       ` [RFC 1/3] lib/vsprintf.c: pull out padding code from dentry_name() Rasmus Villemoes
2015-10-09  9:14                       ` [RFC 2/3] lib/vsprintf.c: move string() below widen_string() Rasmus Villemoes
2015-10-09  9:14                       ` [RFC 3/3] lib/vsprintf.c: eliminate potential race in string() Rasmus Villemoes
2015-10-10  7:47                       ` [RFC 0/3] eliminate potential race in string() (was: [PATCH] string: Improve the generic strlcpy() implementation) Ingo Molnar
2015-10-19 12:42     ` [PATCH] string: Improve the generic strlcpy() implementation Rasmus Villemoes
2015-10-19 16:24       ` Chris Metcalf
  -- strict thread matches above, loose matches on Subject: below --
2015-10-05 15:38 Alexey Dobriyan
2015-10-05 16:11 ` Ingo Molnar
2015-10-05 16:13   ` Ingo Molnar
     [not found] ` <CA+55aFyTVJfCt00gYJpiQW5kqPaRGJ93JmfRRni-73zCf5ivqg@mail.gmail.com>
2015-10-05 16:22   ` Ingo Molnar
2015-10-05 16:28     ` Ingo Molnar
2015-10-05 20:40     ` Linus Torvalds

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=20151005140443.GA5391@gmail.com \
    --to=mingo@kernel.org \
    --cc=a.p.zijlstra@chello.nl \
    --cc=bp@alien8.de \
    --cc=cmetcalf@ezchip.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /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.