aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Zhuravlev <[email protected]>2010-06-02 22:01:14 -0700
committerBrian Behlendorf <[email protected]>2010-06-03 09:06:55 -0700
commit1b4ad25e2f29172c86d3293b61f0c5232d4a2da8 (patch)
treecff3cadd022593ccb32692843bb9b5382af41b7e
parent8a1c9a02fb66ac5885990ec4d82faf03f820085b (diff)
Stack overflow on 64-bit modulus operations on 32-bit architectures.
Running 'zpool create' on a 32-bit machine with an SPL compiled with gcc 4.4.4 led to a stack overlow. This turned out to be due to some sort of 'optimization' by gcc: uint64_t __umoddi3(uint64_t dividend, uint64_t divisor) { return dividend - divisor * (dividend / divisor); } This code was supposed to be using __udivdi3 to implement /, but gcc instead implemented it via __umoddi3 itself. Signed-off-by: Brian Behlendorf <[email protected]>
-rw-r--r--module/spl/spl-generic.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/module/spl/spl-generic.c b/module/spl/spl-generic.c
index 29b698889..9916051de 100644
--- a/module/spl/spl-generic.c
+++ b/module/spl/spl-generic.c
@@ -96,7 +96,8 @@ EXPORT_SYMBOL(highbit);
* Implementation of 64 bit division for 32-bit machines.
*/
#if BITS_PER_LONG == 32
-uint64_t __udivdi3(uint64_t dividend, uint64_t divisor)
+uint64_t
+__udivdi3(uint64_t dividend, uint64_t divisor)
{
#if defined(HAVE_DIV64_64) /* 2.6.22 - 2.6.25 API */
return div64_64(dividend, divisor);
@@ -125,9 +126,10 @@ EXPORT_SYMBOL(__udivdi3);
/*
* Implementation of 64 bit modulo for 32-bit machines.
*/
-uint64_t __umoddi3(uint64_t dividend, uint64_t divisor)
+uint64_t
+__umoddi3(uint64_t dividend, uint64_t divisor)
{
- return dividend - divisor * (dividend / divisor);
+ return (dividend - (divisor * __udivdi3(dividend, divisor)));
}
EXPORT_SYMBOL(__umoddi3);
#endif /* BITS_PER_LONG */