From d8c303fe0a4e18ffa1444ea14f255b5df92685da Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 11 Jan 2008 15:27:03 +0000 Subject: [PATCH] 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 --- manifest | 12 +++++------ manifest.uuid | 2 +- src/vdbemem.c | 58 ++++++++++++++++++++++++++++++++------------------- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/manifest b/manifest index 1d5a0c48d9..a36016af58 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 548aa85c6a..da894ad9cb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6de0ee49073c7a47d5e10495b569b33df76d1448 \ No newline at end of file +4744257d3cd2dd96485fde6d9f60542714383421 \ No newline at end of file diff --git a/src/vdbemem.c b/src/vdbemem.c index db6cb84b8d..443819237a 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -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); -- 2.47.3