]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Do explicit range tests before attempting to convert a 64-bit float
authordrh <drh@noemail.net>
Fri, 11 Jan 2008 15:27:03 +0000 (15:27 +0000)
committerdrh <drh@noemail.net>
Fri, 11 Jan 2008 15:27:03 +0000 (15:27 +0000)
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
manifest.uuid
src/vdbemem.c

index 1d5a0c48d9b9e11699ded2f6454af0a9ac894cf2..a36016af58d8e501fc9896d919e89af21a98c22c 100644 (file)
--- 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
index 548aa85c6aeaa1177e8001b8a2ce10418ba9c38d..da894ad9cbcff0423b664bf2b462e551aa6d163d 100644 (file)
@@ -1 +1 @@
-6de0ee49073c7a47d5e10495b569b33df76d1448
\ No newline at end of file
+4744257d3cd2dd96485fde6d9f60542714383421
\ No newline at end of file
index db6cb84b8d8abbd243384f2dce3da2397f7a0cde..443819237a03e9df0573fc837a5a294bcdd74ea3 100644 (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);