1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

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
This commit is contained in:
drh
2016-09-20 22:04:05 +00:00
parent d8992cef36
commit 09952c6490
4 changed files with 47 additions and 35 deletions

View File

@@ -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;
}