Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ata: sata_sx4: fix pdc20621_get_from_dimm() on 64-bit

gcc warns about a memcpy() with overlapping pointers because of an
incorrect size calculation:

In file included from include/linux/string.h:369,
from drivers/ata/sata_sx4.c:66:
In function 'memcpy_fromio',
inlined from 'pdc20621_get_from_dimm.constprop' at drivers/ata/sata_sx4.c:962:2:
include/linux/fortify-string.h:97:33: error: '__builtin_memcpy' accessing 4294934464 bytes at offsets 0 and [16, 16400] overlaps 6442385281 bytes at offset -2147450817 [-Werror=restrict]
97 | #define __underlying_memcpy __builtin_memcpy
| ^
include/linux/fortify-string.h:620:9: note: in expansion of macro '__underlying_memcpy'
620 | __underlying_##op(p, q, __fortify_size); \
| ^~~~~~~~~~~~~
include/linux/fortify-string.h:665:26: note: in expansion of macro '__fortify_memcpy_chk'
665 | #define memcpy(p, q, s) __fortify_memcpy_chk(p, q, s, \
| ^~~~~~~~~~~~~~~~~~~~
include/asm-generic/io.h:1184:9: note: in expansion of macro 'memcpy'
1184 | memcpy(buffer, __io_virt(addr), size);
| ^~~~~~

The problem here is the overflow of an unsigned 32-bit number to a
negative that gets converted into a signed 'long', keeping a large
positive number.

Replace the complex calculation with a more readable min() variant
that avoids the warning.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>

authored by

Arnd Bergmann and committed by
Damien Le Moal
52f80bb1 39cd87c4

+2 -4
+2 -4
drivers/ata/sata_sx4.c
··· 957 957 958 958 offset -= (idx * window_size); 959 959 idx++; 960 - dist = ((long) (window_size - (offset + size))) >= 0 ? size : 961 - (long) (window_size - offset); 960 + dist = min(size, window_size - offset); 962 961 memcpy_fromio(psource, dimm_mmio + offset / 4, dist); 963 962 964 963 psource += dist; ··· 1004 1005 readl(mmio + PDC_DIMM_WINDOW_CTLR); 1005 1006 offset -= (idx * window_size); 1006 1007 idx++; 1007 - dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : 1008 - (long) (window_size - offset); 1008 + dist = min(size, window_size - offset); 1009 1009 memcpy_toio(dimm_mmio + offset / 4, psource, dist); 1010 1010 writel(0x01, mmio + PDC_GENERAL_CTLR); 1011 1011 readl(mmio + PDC_GENERAL_CTLR);