SQLite

Check-in [2c63588b45]
Login

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

Overview
Comment:Make sure strings returned by sqlite3_value_text() and sqlite3_value_text16() are always '\000'-terminated. (CVS 3391)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2c63588b45f4e1ab9b9f1b72c901f3800433424a
User & Date: drh 2006-09-04 15:53:53.000
Context
2006-09-04
18:54
Fix a bug in the new misc6.test script. Fix error messages when not compiled with memory debugging enabled. Ticket #1957. (CVS 3392) (check-in: 9fb92024bf user: drh tags: trunk)
15:53
Make sure strings returned by sqlite3_value_text() and sqlite3_value_text16() are always '\000'-terminated. (CVS 3391) (check-in: 2c63588b45 user: drh tags: trunk)
2006-09-02
22:14
Fix bugs in test scripts so that fulltest will pass. (CVS 3390) (check-in: 367bd8376f user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/test1.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.218 2006/09/02 14:50:24 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>








|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.219 2006/09/04 15:53:53 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

437
438
439
440
441
442
443




























444
445
446
447
448
449
450
    if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
      sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
          sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
      break;
    }
  }
}





























/*
** A structure into which to accumulate text.
*/
struct dstr {
  int nAlloc;  /* Space allocated */
  int nUsed;   /* Space used */







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







437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
    if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
      sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
          sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
      break;
    }
  }
}

/*
** These are test functions.    hex8() interprets its argument as
** UTF8 and returns a hex encoding.  hex16le() interprets its argument
** as UTF16le and returns a hex encoding.
*/
static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
  const unsigned char *z;
  int i;
  char zBuf[200];
  z = sqlite3_value_text(argv[0]);
  for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){
    sprintf(&zBuf[i*2], "%02x", z[i]&0xff);
  }
  zBuf[i*2] = 0;
  sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
}
static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
  const unsigned short int *z;
  int i;
  char zBuf[400];
  z = sqlite3_value_text16(argv[0]);
  for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
    sprintf(&zBuf[i*4], "%04x", z[i]&0xff);
  }
  zBuf[i*4] = 0;
  sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
}

/*
** A structure into which to accumulate text.
*/
struct dstr {
  int nAlloc;  /* Space allocated */
  int nUsed;   /* Space used */
544
545
546
547
548
549
550




551
552
553
554
555
556
557
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " DB\"", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0, 
        ifnullFunc, 0, 0);





#ifndef SQLITE_OMIT_UTF16
  /* Use the sqlite3_create_function16() API here. Mainly for fun, but also 
  ** because it is not tested anywhere else. */
  if( rc==SQLITE_OK ){
    sqlite3_value *pVal;
#ifdef SQLITE_MEMDEBUG







>
>
>
>







572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " DB\"", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
  rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0, 
        ifnullFunc, 0, 0);
  rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0, 
        hex8Func, 0, 0);
  rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0, 
        hex16Func, 0, 0);

#ifndef SQLITE_OMIT_UTF16
  /* Use the sqlite3_create_function16() API here. Mainly for fun, but also 
  ** because it is not tested anywhere else. */
  if( rc==SQLITE_OK ){
    sqlite3_value *pVal;
#ifdef SQLITE_MEMDEBUG
1413
1414
1415
1416
1417
1418
1419

1420
1421
1422
1423
1424
1425
1426
}

/*
** This is the "static_bind_value" that variables are bound to when
** the FLAG option of sqlite3_bind is "static"
*/
static char *sqlite_static_bind_value = 0;


/*
** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
**
** Sets the value of the IDX-th occurance of "?" in the original SQL
** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
** ignored and the value is set to NULL.  If FLAGS=="static" then







>







1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
}

/*
** This is the "static_bind_value" that variables are bound to when
** the FLAG option of sqlite3_bind is "static"
*/
static char *sqlite_static_bind_value = 0;
static int sqlite_static_bind_nbyte = 0;

/*
** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
**
** Sets the value of the IDX-th occurance of "?" in the original SQL
** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
** ignored and the value is set to NULL.  If FLAGS=="static" then
1445
1446
1447
1448
1449
1450
1451



1452
1453
1454
1455
1456
1457
1458
  }
  if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
  if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
  if( strcmp(argv[4],"null")==0 ){
    rc = sqlite3_bind_null(pStmt, idx);
  }else if( strcmp(argv[4],"static")==0 ){
    rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);



  }else if( strcmp(argv[4],"normal")==0 ){
    rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
  }else if( strcmp(argv[4],"blob10")==0 ){
    rc = sqlite3_bind_text(pStmt, idx, "abc\000xyz\000pq", 10, SQLITE_STATIC);
  }else{
    Tcl_AppendResult(interp, "4th argument should be "
        "\"null\" or \"static\" or \"normal\"", 0);







>
>
>







1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
  }
  if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
  if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
  if( strcmp(argv[4],"null")==0 ){
    rc = sqlite3_bind_null(pStmt, idx);
  }else if( strcmp(argv[4],"static")==0 ){
    rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
  }else if( strcmp(argv[4],"static-nbytes")==0 ){
    rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value,
                                       sqlite_static_bind_nbyte, 0);
  }else if( strcmp(argv[4],"normal")==0 ){
    rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
  }else if( strcmp(argv[4],"blob10")==0 ){
    rc = sqlite3_bind_text(pStmt, idx, "abc\000xyz\000pq", 10, SQLITE_STATIC);
  }else{
    Tcl_AppendResult(interp, "4th argument should be "
        "\"null\" or \"static\" or \"normal\"", 0);
3964
3965
3966
3967
3968
3969
3970


3971
3972
3973
3974
3975
3976
3977
#endif
#ifndef SQLITE_OMIT_DISKIO
  Tcl_LinkVar(interp, "sqlite_opentemp_count",
      (char*)&sqlite3_opentemp_count, TCL_LINK_INT);
#endif
  Tcl_LinkVar(interp, "sqlite_static_bind_value",
      (char*)&sqlite_static_bind_value, TCL_LINK_STRING);


  Tcl_LinkVar(interp, "sqlite_temp_directory",
      (char*)&sqlite3_temp_directory, TCL_LINK_STRING);
  Tcl_LinkVar(interp, "bitmask_size",
      (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
#if OS_UNIX
  Tcl_LinkVar(interp, "sqlite_sync_count",
      (char*)&sqlite3_sync_count, TCL_LINK_INT);







>
>







4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
#endif
#ifndef SQLITE_OMIT_DISKIO
  Tcl_LinkVar(interp, "sqlite_opentemp_count",
      (char*)&sqlite3_opentemp_count, TCL_LINK_INT);
#endif
  Tcl_LinkVar(interp, "sqlite_static_bind_value",
      (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
  Tcl_LinkVar(interp, "sqlite_static_bind_nbyte",
      (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
  Tcl_LinkVar(interp, "sqlite_temp_directory",
      (char*)&sqlite3_temp_directory, TCL_LINK_STRING);
  Tcl_LinkVar(interp, "bitmask_size",
      (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
#if OS_UNIX
  Tcl_LinkVar(interp, "sqlite_sync_count",
      (char*)&sqlite3_sync_count, TCL_LINK_INT);
Changes to src/vdbemem.c.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  /* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
  ** then the encoding of the value may not have changed.
  */
  rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
  assert(rc==SQLITE_OK    || rc==SQLITE_NOMEM);
  assert(rc==SQLITE_OK    || pMem->enc!=desiredEnc);
  assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);

  if( rc==SQLITE_NOMEM ){
/*
    sqlite3VdbeMemRelease(pMem);
    pMem->flags = MEM_Null;
    pMem->z = 0;
*/
  }
  return rc;
#endif
}

/*
** Make the given Mem object MEM_Dyn.
**







<
<
<
<
<
<
<
<







46
47
48
49
50
51
52








53
54
55
56
57
58
59
  /* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
  ** then the encoding of the value may not have changed.
  */
  rc = sqlite3VdbeMemTranslate(pMem, desiredEnc);
  assert(rc==SQLITE_OK    || rc==SQLITE_NOMEM);
  assert(rc==SQLITE_OK    || pMem->enc!=desiredEnc);
  assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);








  return rc;
#endif
}

/*
** Make the given Mem object MEM_Dyn.
**
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154



155
156
157
158
159
160
161
  return SQLITE_OK;
}

/*
** Make sure the given Mem is \u0000 terminated.
*/
int sqlite3VdbeMemNulTerminate(Mem *pMem){
  /* In SQLite, a string without a nul terminator occurs when a string
  ** is loaded from disk (in this case the memory management is ephemeral),
  ** or when it is supplied by the user as a bound variable or function
  ** return value. Therefore, the memory management of the string must be
  ** either ephemeral, static or controlled by a user-supplied destructor.
  */
  assert(                         
    !(pMem->flags&MEM_Str) ||                /* it's not a string, or      */
    (pMem->flags&MEM_Term) ||                /* it's nul term. already, or */
    (pMem->flags&(MEM_Ephem|MEM_Static)) ||  /* it's static or ephem, or   */
    (pMem->flags&MEM_Dyn && pMem->xDel)      /* external management        */
  );
  if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
    return SQLITE_OK;   /* Nothing to do */
  }

  if( pMem->flags & (MEM_Static|MEM_Ephem) ){
    return sqlite3VdbeMemMakeWriteable(pMem);
  }else{
    char *z = sqliteMalloc(pMem->n+2);
    if( !z ) return SQLITE_NOMEM;
    memcpy(z, pMem->z, pMem->n);
    z[pMem->n] = 0;
    z[pMem->n+1] = 0;

    pMem->xDel(pMem->z);



    pMem->xDel = 0;
    pMem->z = z;
  }
  return SQLITE_OK;
}

/*







<
<
<
<
<
<
<
<
<
<
<
<



<








>
|
>
>
>







115
116
117
118
119
120
121












122
123
124

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  return SQLITE_OK;
}

/*
** Make sure the given Mem is \u0000 terminated.
*/
int sqlite3VdbeMemNulTerminate(Mem *pMem){












  if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
    return SQLITE_OK;   /* Nothing to do */
  }

  if( pMem->flags & (MEM_Static|MEM_Ephem) ){
    return sqlite3VdbeMemMakeWriteable(pMem);
  }else{
    char *z = sqliteMalloc(pMem->n+2);
    if( !z ) return SQLITE_NOMEM;
    memcpy(z, pMem->z, pMem->n);
    z[pMem->n] = 0;
    z[pMem->n+1] = 0;
    if( pMem->xDel ){
      pMem->xDel(pMem->z);
    }else{
      sqliteFree(pMem->z);
    }
    pMem->xDel = 0;
    pMem->z = z;
  }
  return SQLITE_OK;
}

/*
778
779
780
781
782
783
784


785
786
787
788
789
790
791
792
    sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
    if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
      assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
      if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
        return 0;
      }
    }


  }else if( !(pVal->flags&MEM_Blob) ){
    sqlite3VdbeMemStringify(pVal, enc);
    assert( 0==(1&(int)pVal->z) );
  }
  assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || sqlite3MallocFailed() );
  if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
    return pVal->z;
  }else{







>
>
|







761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
    sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
    if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
      assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
      if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
        return 0;
      }
    }
    sqlite3VdbeMemNulTerminate(pVal);
  }else{
    assert( (pVal->flags&MEM_Blob)==0 );
    sqlite3VdbeMemStringify(pVal, enc);
    assert( 0==(1&(int)pVal->z) );
  }
  assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || sqlite3MallocFailed() );
  if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
    return pVal->z;
  }else{
Added test/misc6.test.


























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 2006 September 4
#
# 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.
#
# This file implements tests to make sure sqlite3_value_text()
# always returns a null-terminated string.
#
# $Id: misc6.test,v 1.1 2006/09/04 15:53:53 drh Exp $

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

do_test misc6-1.1 {
  set DB [sqlite3_connection_pointer db]
  sqlite3_create_function $DB
  set STMT [sqlite3_prepare $DB {SELECT hex8(?)} -1 DUMMY]
  set sqlite_static_bind_value {0123456789}
  set sqlite_static_bind_nbyte 5
  sqlite_bind $STMT 1 {} static-nbytes
  sqlite3_step $STMT
} SQLITE_ROW
do_test misc6-1.2 {
  sqlite3_column_text $STMT 0
} {3031323334}
do_test misc6-1.3 {
  sqlite3_finalize $STMT
  set STMT [sqlite3_prepare $DB {SELECT hex16(?)} -1 DUMMY]
  set sqlite_static_bind_value {0123456789}
  set sqlite_static_bind_nbyte 5
  sqlite_bind $STMT 1 {} static-nbytes
  sqlite3_step $STMT
} SQLITE_ROW
do_test misc6-1.4 {
  sqlite3_column_text $STMT 0
} {00300031003200330034}

finish_test