SQLite

Check-in [81342fa6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:On x64 hardware, round-trip uint64_t→double→uint64_t conversions fail for values greater than UINT64_MAX-2047. This caused the SQLite text-to-float converter routine to give incorrect results for values between '1.8446744073709550592eNNN' and '1.8446744073709551609eNNN' for any exponent NNN. This problem was introduced by check-in [761d8fd18b0ee868] and first appeared in version 3.47.0 and was reported by forum post 569a7209179a7f5e. Fixed by this check-in.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 81342fa6dd03fffbe7d4d699ff049dcef4d30344578bb6f91cb58a4e5a4f6036
User & Date: drh 2024-12-07 14:48:55
References
2024-12-07
19:06
A cleaner and more robust solution to the floating-point conversion problem originally fixed by [81342fa6dd03fffb]. (check-in: 351de57f user: drh tags: trunk)
Context
2024-12-09
11:12
Fix an obscure problem with multiple outer joins, ON clauses and query flattening. Forum thread 5c8a069d23. (Closed-Leaf check-in: 289daf6c user: dan tags: forum-5c8a069d23-fix)
2024-12-07
16:53
Fix harmless compiler warning caused by the previous check-in. (check-in: 462700ae user: drh tags: trunk)
14:51
On x64 hardware, round-trip uint64_t→double→uint64_t conversions fail for values greater than UINT64_MAX-2047. This caused the SQLite text-to-float converter routine to give incorrect results for values between '1.8446744073709550592eNNN' and '1.8446744073709551609eNNN' for any exponent NNN. Fixed by this check-in. (check-in: 17537a98 user: drh tags: branch-3.47)
14:48
On x64 hardware, round-trip uint64_t→double→uint64_t conversions fail for values greater than UINT64_MAX-2047. This caused the SQLite text-to-float converter routine to give incorrect results for values between '1.8446744073709550592eNNN' and '1.8446744073709551609eNNN' for any exponent NNN. This problem was introduced by check-in [761d8fd18b0ee868] and first appeared in version 3.47.0 and was reported by forum post 569a7209179a7f5e. Fixed by this check-in. (check-in: 81342fa6 user: drh tags: trunk)
2024-12-06
18:35
Add the SQLITE_PREPARE_DONT_LOG option for sqlite3_prepare_v3(), that prevents errors in the compilation of the SQL from being sent to sqlite3_log(). (check-in: 87040342 user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch
Changes to src/util.c.
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655

656
657
658
659
660





661
662
663
664
665
666
667
    goto atof_return;
  }

  /* adjust exponent by d, and update sign */
  e = (e*esign) + d;

  /* Try to adjust the exponent to make it smaller */
  while( e>0 && s<(LARGEST_UINT64/10) ){
    s *= 10;
    e--;
  }
  while( e<0 && (s%10)==0 ){
    s /= 10;
    e++;
  }

  rr[0] = (double)s;

  s2 = (u64)rr[0];
#if defined(_MSC_VER) && _MSC_VER<1700
  if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
#endif
  rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);





  if( e>0 ){
    while( e>=100  ){
      e -= 100;
      dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
    }
    while( e>=10   ){
      e -= 10;







|









>
|

|

|
>
>
>
>
>







639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
    goto atof_return;
  }

  /* adjust exponent by d, and update sign */
  e = (e*esign) + d;

  /* Try to adjust the exponent to make it smaller */
  while( e>0 && s<((LARGEST_UINT64-0x7ff)/10) ){
    s *= 10;
    e--;
  }
  while( e<0 && (s%10)==0 ){
    s /= 10;
    e++;
  }

  rr[0] = (double)s;
  if( s<(LARGEST_UINT64-0x7ff) ){
    s2 = (u64)rr[0];
#if defined(_MSC_VER) && _MSC_VER<1700
    if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
#endif
    rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
  }else{
    s2 = s;
    rr[1] = 0.0;
  }

  if( e>0 ){
    while( e>=100  ){
      e -= 100;
      dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
    }
    while( e>=10   ){
      e -= 10;
Changes to test/atof1.test.
77
78
79
80
81
82
83






































84
85
86
  CREATE INDEX i1 ON t1(a);
  SELECT count(*) FROM t1 WHERE substr(a,',');
} {1}
# 2020-08-27 OSSFuzz find related to the above.
do_execsql_test atof1-2.40 {
  SELECT randomblob(0) - 1;
} {-1}








































finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  CREATE INDEX i1 ON t1(a);
  SELECT count(*) FROM t1 WHERE substr(a,',');
} {1}
# 2020-08-27 OSSFuzz find related to the above.
do_execsql_test atof1-2.40 {
  SELECT randomblob(0) - 1;
} {-1}

# 2024-12-07 https://sqlite.org/forum/forumpost/569a7209179a7f5e
# Incorrect conversion of floating point or integer literals that
# have significant digits that begin with 1844674407370955 followed
# by more digits in the range 0592 throgh 1609.
#
do_execsql_test atof-3.1 {
  WITH RECURSIVE bigval(i,vtxt) AS (
    SELECT 0, '18446744073709550000'
    UNION ALL
    SELECT i+1, format('1844674407370955%04d',i+1) FROM bigval
     WHERE i+1<=9999
  )
  SELECT vtxt, CAST(vtxt AS REAL) FROM bigval
   WHERE CAST(vtxt AS REAL) NOT GLOB '1.8446744073709[56]*';
} {}
do_execsql_test atof-3.2 {
  WITH RECURSIVE bigval(i,vtxt) AS (
    SELECT 0, '18.446744073709550000'
    UNION ALL
    SELECT i+1, format('18.44674407370955%04d',i+1) FROM bigval
     WHERE i+1<=9999
  )
  SELECT vtxt, CAST(vtxt AS REAL) FROM bigval
   WHERE CAST(vtxt AS REAL) NOT GLOB '18.446744073709*';
} {}
do_execsql_test atof-3.3 {
  WITH RECURSIVE exp(n,v1,v2) AS (
    SELECT -200, '1.8446744073709550592e-200', '1.8446744073709551609e-200'
    UNION ALL
    SELECT n+1, ('1.8446744073709550592e'||n),('1.8446744073709551609e'||n)
      FROM exp WHERE n<200
  )
  SELECT n, v1, v2
    FROM exp
   WHERE format('%.10e',CAST(v1 AS REAL)) NOT GLOB '1.8446*'
      OR format('%.10e',CAST(v2 AS REAL)) NOT GLOB '1.8446*';
} {}


finish_test