Do explicit range tests before attempting to convert a 64-bit float

into a 64-bit integer.  Some systems (windows) seem to throw exceptions
if the conversion is out of range.  Ticket #2880. (CVS 4706)

FossilOrigin-Name: 4744257d3cd2dd96485fde6d9f60542714383421
This commit is contained in:
drh 2008-01-11 15:27:03 +00:00
parent efe3d656b6
commit d8c303fe0a
3 changed files with 43 additions and 29 deletions

View File

@ -1,5 +1,5 @@
C Attempt\sto\swork\saround\sa\sbug\sin\sthe\sBorland\sBCC\s5.5.1\scompiler.\s\sTicket\s#2880.\s(CVS\s4705)
D 2008-01-11T00:06:11
C Do\sexplicit\srange\stests\sbefore\sattempting\sto\sconvert\sa\s64-bit\sfloat\ninto\sa\s64-bit\sinteger.\s\sSome\ssystems\s(windows)\sseem\sto\sthrow\sexceptions\nif\sthe\sconversion\sis\sout\sof\srange.\s\sTicket\s#2880.\s(CVS\s4706)
D 2008-01-11T15:27:03
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -175,7 +175,7 @@ F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
F src/vdbeaux.c db33a4c2477546da05e772352be43896d24d51d5
F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c 3da7f7fa7f2ab06a5cbaff132898b07e4d095220
F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e
F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a
F src/where.c 9705df3c2b78ea8e02a768be8ac5d3f7a2902f1e
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
@ -605,7 +605,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P 8cbd46517f407b3b1ce187b623db10f00aa415ea
R 911083b5c48b851385eee47775792145
P 6de0ee49073c7a47d5e10495b569b33df76d1448
R 72b005345d91bd390788cc14572cdea6
U drh
Z ec1836639b43428a4a6ed94e2aced93a
Z f60ae65829aa8eb88bba7196814bec78

View File

@ -1 +1 @@
6de0ee49073c7a47d5e10495b569b33df76d1448
4744257d3cd2dd96485fde6d9f60542714383421

View File

@ -288,6 +288,38 @@ void sqlite3VdbeMemRelease(Mem *p){
}
}
/*
** Convert a 64-bit IEEE double into a 64-bit signed integer.
** If the double is too large, return 0x8000000000000000.
**
** Most systems appear to do this simply by assigning
** variables and without the extra range tests. But
** there are reports that windows throws an expection
** if the floating point value is out of range. (See ticket #2880.)
** Because we do not completely understand the problem, we will
** take the conservative approach and always do range tests
** before attempting the conversion.
*/
static i64 doubleToInt64(double r){
/*
** Many compilers we encounter do not define constants for the
** minimum and maximum 64-bit integers, or they define them
** inconsistently. And many do not understand the "LL" notation.
** So we define our own static constants here using nothing
** larger than a 32-bit integer constant.
*/
static const i64 maxInt = (((i64)0x7fffffff)<<32)|0xffffffff;
static const i64 minInt = ((i64)0x80000000)<<32;
if( r<(double)minInt ){
return minInt;
}else if( r>(double)maxInt ){
return minInt;
}else{
return (i64)r;
}
}
/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
@ -305,7 +337,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
if( flags & MEM_Int ){
return pMem->u.i;
}else if( flags & MEM_Real ){
return (i64)pMem->r;
return doubleToInt64(pMem->r);
}else if( flags & (MEM_Str|MEM_Blob) ){
i64 value;
pMem->flags |= MEM_Str;
@ -356,26 +388,8 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
assert( pMem->flags & MEM_Real );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
/* It is reported (in ticket #2880) that the BCC 5.5.1 compiler
** will corrupt a floating point number on the right-hand side
** of an assignment if the lvalue for the assignment is an integer.
**
** We will attempt to work around this bug in the Borland compiler
** by moving the value into a temporary variable first so that if
** the assignment into the integer really does corrupt the right-hand
** side value, it will corrupt a temporary variable that we do not
** care about.
*/
#ifdef __BORLANDC__
{
double r = pMem->r;
pMem->u.i = r;
}
#else
pMem->u.i = pMem->r;
#endif
if( ((double)pMem->u.i)==pMem->r ){
pMem->u.i = doubleToInt64(pMem->r);
if( pMem->r==(double)pMem->u.i ){
pMem->flags |= MEM_Int;
}
}
@ -414,7 +428,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
r1 = sqlite3VdbeRealValue(pMem);
i = (i64)r1;
i = doubleToInt64(r1);
r2 = (double)i;
if( r1==r2 ){
sqlite3VdbeMemIntegerify(pMem);