• Linus Torvalds's avatar
    iov_iter: fix build issue due to possible type mis-match · 1c27f1fc
    Linus Torvalds authored
    Commit 6c776766 ("iov_iter: Fix iter_xarray_get_pages{,_alloc}()")
    introduced a problem on some 32-bit architectures (at least arm, xtensa,
    csky,sparc and mips), that have a 'size_t' that is 'unsigned int'.
    
    The reason is that we now do
    
        min(nr * PAGE_SIZE - offset, maxsize);
    
    where 'nr' and 'offset' and both 'unsigned int', and PAGE_SIZE is
    'unsigned long'.  As a result, the normal C type rules means that the
    first argument to 'min()' ends up being 'unsigned long'.
    
    In contrast, 'maxsize' is of type 'size_t'.
    
    Now, 'size_t' and 'unsigned long' are always the same physical type in
    the kernel, so you'd think this doesn't matter, and from an actual
    arithmetic standpoint it doesn't.
    
    But on 32-bit architectures 'size_t' is commonly 'unsigned int', even if
    it could also be 'unsigned long'.  In that situation, both are unsigned
    32-bit types, but they are not the *same* type.
    
    And as a result 'min()' will complain about the distinct types (ignore
    the "pointer types" part of the error message: that's an artifact of the
    way we have made 'min()' check types for being the same):
    
      lib/iov_iter.c: In function 'iter_xarray_get_pages':
      include/linux/minmax.h:20:35: error: comparison of distinct pointer types lacks a cast [-Werror]
         20 |         (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
            |                                   ^~
      lib/iov_iter.c:1464:16: note: in expansion of macro 'min'
       1464 |         return min(nr * PAGE_SIZE - offset, maxsize);
            |                ^~~
    
    This was not visible on 64-bit architectures (where we always define
    'size_t' to be 'unsigned long').
    
    Force these cases to use 'min_t(size_t, x, y)' to make the type explicit
    and avoid the issue.
    
    [ Nit-picky note: technically 'size_t' doesn't have to match 'unsigned
      long' arithmetically. We've certainly historically seen environments
      with 16-bit address spaces and 32-bit 'unsigned long'.
    
      Similarly, even in 64-bit modern environments, 'size_t' could be its
      own type distinct from 'unsigned long', even if it were arithmetically
      identical.
    
      So the above type commentary is only really descriptive of the kernel
      environment, not some kind of universal truth for the kinds of wild
      and crazy situations that are allowed by the C standard ]
    Reported-by: default avatarSudip Mukherjee <sudipm.mukherjee@gmail.com>
    Link: https://lore.kernel.org/all/YqRyL2sIqQNDfky2@debian/
    Cc: Jeff Layton <jlayton@kernel.org>
    Cc: David Howells <dhowells@redhat.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    1c27f1fc
iov_iter.c 49.2 KB