SQLite

Check-in [b0fb4a3cf6]
Login

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

Overview
Comment:Fix a potential buffer overrun in the replace() function. (CVS 3947)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b0fb4a3cf6ddbc17ccd0c719b34a720d9090bc93
User & Date: danielk1977 2007-05-08 14:39:04.000
Context
2007-05-08
14:51
Add the max_page_count pragma used to limit the maximum size of a database file. Untested. (CVS 3948) (check-in: b1b74f0668 user: drh tags: trunk)
14:39
Fix a potential buffer overrun in the replace() function. (CVS 3947) (check-in: b0fb4a3cf6 user: danielk1977 tags: trunk)
13:58
Add more code to enforce the limits specified in limits.h. (CVS 3946) (check-in: c59d436095 user: drh tags: trunk)
Changes
Unified Diff Show Whitespace Changes Patch
Changes to src/func.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.147 2007/05/08 12:12:17 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
/* #include <math.h> */
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.148 2007/05/08 14:39:04 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
/* #include <math.h> */
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"
749
750
751
752
753
754
755
756

757
758
759
760
761
762
763
764





765
766
767
768
769
770
771
  if( zPattern==0 || zPattern[0]==0 ) return;
  nRep = sqlite3_value_bytes(argv[2]);
  zRep = sqlite3_value_text(argv[2]);
  if( zRep==0 ) return;
  if( nPattern>=nRep ){
    nOut = nStr;
  }else{
    nOut = (nStr/nPattern + 1)*nRep;

  }
  zOut = sqlite3_malloc(nOut+1);
  if( zOut==0 ) return;
  loopLimit = nStr - nPattern;  
  for(i=j=0; i<=loopLimit; i++){
    if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
      zOut[j++] = zStr[i];
    }else{





      memcpy(&zOut[j], zRep, nRep);
      j += nRep;
      i += nPattern-1;
    }
  }
  memcpy(&zOut[j], &zStr[i], nStr-i);
  j += nStr - i;







|
>








>
>
>
>
>







749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
  if( zPattern==0 || zPattern[0]==0 ) return;
  nRep = sqlite3_value_bytes(argv[2]);
  zRep = sqlite3_value_text(argv[2]);
  if( zRep==0 ) return;
  if( nPattern>=nRep ){
    nOut = nStr;
  }else{
    i64 nOut64 = (i64)(nStr/nPattern + 1) * (i64)nRep;
    nOut = ((nOut64>SQLITE_MAX_LENGTH) ? SQLITE_MAX_LENGTH : nOut64);
  }
  zOut = sqlite3_malloc(nOut+1);
  if( zOut==0 ) return;
  loopLimit = nStr - nPattern;  
  for(i=j=0; i<=loopLimit; i++){
    if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
      zOut[j++] = zStr[i];
    }else{
      if( (j+nRep+loopLimit-i)>SQLITE_MAX_LENGTH ){
        sqlite3_result_error(context, "replace() is too large", -1);
        sqlite3_free(zOut);
        return;
      }
      memcpy(&zOut[j], zRep, nRep);
      j += nRep;
      i += nPattern-1;
    }
  }
  memcpy(&zOut[j], &zStr[i], nStr-i);
  j += nStr - i;
Changes to test/func.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing built-in functions.
#
# $Id: func.test,v 1.64 2007/05/07 16:58:02 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create a table to work with.
#
do_test func-0.0 {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing built-in functions.
#
# $Id: func.test,v 1.65 2007/05/08 14:39:04 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create a table to work with.
#
do_test func-0.0 {
329
330
331
332
333
334
335

336
337
338
339
340
341
342
} {00112233445566778899AABBCCDDEEFF}
do_test func-9.11 {
  execsql {SELECT hex(replace('abcdefg','ef','12'))}
} {61626364313267}
do_test func-9.12 {
  execsql {SELECT hex(replace('abcdefg','','12'))}
} {{}}

do_test func-9.13 {
  execsql {SELECT hex(replace('aabcdefg','a','aaa'))}
} {616161616161626364656667}

# Use the "sqlite_register_test_function" TCL command which is part of
# the text fixture in order to verify correct operation of some of
# the user-defined SQL function APIs that are not used by the built-in







>







329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
} {00112233445566778899AABBCCDDEEFF}
do_test func-9.11 {
  execsql {SELECT hex(replace('abcdefg','ef','12'))}
} {61626364313267}
do_test func-9.12 {
  execsql {SELECT hex(replace('abcdefg','','12'))}
} {{}}
breakpoint
do_test func-9.13 {
  execsql {SELECT hex(replace('aabcdefg','a','aaa'))}
} {616161616161626364656667}

# Use the "sqlite_register_test_function" TCL command which is part of
# the text fixture in order to verify correct operation of some of
# the user-defined SQL function APIs that are not used by the built-in
778
779
780
781
782
783
784










785
786
787
788
789
790
791
} {{This is the larger-main test string}}
do_test func-21.8 {
  execsql {
    SELECT replace("aaaaaaa", "a", "0123456789");
  }
} {0123456789012345678901234567890123456789012345678901234567890123456789}











# Tests for the TRIM, LTRIM and RTRIM functions.
#
do_test func-22.1 {
  catchsql {SELECT trim(1,2,3)}
} {1 {wrong number of arguments to function trim()}}
do_test func-22.2 {
  catchsql {SELECT ltrim(1,2,3)}







>
>
>
>
>
>
>
>
>
>







779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
} {{This is the larger-main test string}}
do_test func-21.8 {
  execsql {
    SELECT replace("aaaaaaa", "a", "0123456789");
  }
} {0123456789012345678901234567890123456789012345678901234567890123456789}

do_test func-21.9 {
  # Attempt to exploit a buffer-overflow that at one time existed 
  # in the REPLACE function. 
  set ::str "[string repeat A 29998]CC[string repeat A 35537]"
  set ::rep [string repeat B 65536]
  execsql {
    SELECT LENGTH(REPLACE($::str, 'C', $::rep));
  }
} [expr 29998 + 2*65536 + 35537]

# Tests for the TRIM, LTRIM and RTRIM functions.
#
do_test func-22.1 {
  catchsql {SELECT trim(1,2,3)}
} {1 {wrong number of arguments to function trim()}}
do_test func-22.2 {
  catchsql {SELECT ltrim(1,2,3)}