diff options
author | drh <drh@noemail.net> | 2016-09-20 22:04:05 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2016-09-20 22:04:05 +0000 |
commit | 09952c6490fb1004055bd4a1c83d85fa781da1f2 (patch) | |
tree | 4e4f6bc76ae655916985d9d38857bf84400013d4 /src | |
parent | d8992cef36568fcc8b42e5c3c6e4bc7999d8b7db (diff) | |
download | sqlite-09952c6490fb1004055bd4a1c83d85fa781da1f2.tar.gz sqlite-09952c6490fb1004055bd4a1c83d85fa781da1f2.zip |
Improved implementation of 64-bit signed integer multiply that correctly
detects overflow (and promotes to floating-point) in some corner cases.
Fix for ticket [1ec41379c9c1e400]
FossilOrigin-Name: db3ebd7c52cfc5fcc7be00f52e9d7c84719f7b93
Diffstat (limited to 'src')
-rw-r--r-- | src/util.c | 37 |
1 files changed, 11 insertions, 26 deletions
diff --git a/src/util.c b/src/util.c index db6163c3c..e18b84757 100644 --- a/src/util.c +++ b/src/util.c @@ -1305,36 +1305,21 @@ int sqlite3SubInt64(i64 *pA, i64 iB){ return sqlite3AddInt64(pA, -iB); } } -#define TWOPOWER32 (((i64)1)<<32) -#define TWOPOWER31 (((i64)1)<<31) int sqlite3MulInt64(i64 *pA, i64 iB){ i64 iA = *pA; - i64 iA1, iA0, iB1, iB0, r; - - iA1 = iA/TWOPOWER32; - iA0 = iA % TWOPOWER32; - iB1 = iB/TWOPOWER32; - iB0 = iB % TWOPOWER32; - if( iA1==0 ){ - if( iB1==0 ){ - *pA *= iB; - return 0; + if( iB>0 ){ + if( iA>LARGEST_INT64/iB ) return 1; + if( iA<SMALLEST_INT64/iB ) return 1; + }else if( iB<0 ){ + if( iA>0 ){ + if( iB<SMALLEST_INT64/iA ) return 1; + }else if( iA<0 ){ + if( iB==SMALLEST_INT64 ) return 1; + if( iA==SMALLEST_INT64 ) return 1; + if( -iA>LARGEST_INT64/-iB ) return 1; } - r = iA0*iB1; - }else if( iB1==0 ){ - r = iA1*iB0; - }else{ - /* If both iA1 and iB1 are non-zero, overflow will result */ - return 1; } - testcase( r==(-TWOPOWER31)-1 ); - testcase( r==(-TWOPOWER31) ); - testcase( r==TWOPOWER31 ); - testcase( r==TWOPOWER31-1 ); - if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1; - r *= TWOPOWER32; - if( sqlite3AddInt64(&r, iA0*iB0) ) return 1; - *pA = r; + *pA = iA*iB; return 0; } |