On 08/25/2015 11:36 PM, Bill Parker wrote:
> Hello All,
>
>      In reviewing source code files in sqlite 3.8.11.1, I found some
> instances of calls to Tcl_Alloc() which are not checked for a return
> value of NULL, indicating failure in directory '/tea/generic', file
> 'tclsqlite3.c'.  Additionally, in the event of failure, there are
> some cases where memset()/memcpy() is called after Tcl_Alloc(), but
> in the event that Tcl_Alloc() returns NULL, memset()/memcpy() will
> generate a segmentation fault/violation if memset()/memcpy() is called
> with a address location pointing to NULL (see test program below
> the patch file).
>
> The patch file below should catch and handle all conditions where
> Tcl_Alloc() is called, but are NOT checked for a return value of NULL:

Does Tcl_Alloc() actually return NULL if a malloc fails? I thought if 
memory can not be allocated it calls Tcl_Panic() to report an error 
message and then aborts the process.

Dan.



>
> =======================================================================
>
> --- tclsqlite3.c.orig    2015-08-22 18:50:01.656000000 -0700
> +++ tclsqlite3.c    2015-08-22 19:12:05.716000000 -0700
> @@ -380,6 +380,10 @@
>     }
>
>     p = (IncrblobChannel *)Tcl_Alloc(sizeof(IncrblobChannel));
> +  if( !p ){
> +    Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +    return TCL_ERROR;
> +  }
>     p->iSeek = 0;
>     p->pBlob = pBlob;
>
> @@ -439,6 +443,10 @@
>     SqlFunc *p, *pNew;
>     int nName = strlen30(zName);
>     pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
> +  if( !pNew ){
> +    Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +    return NULL;  /*  what should be returned here? */
> +  }
>     pNew->zName = (char*)&pNew[1];
>     memcpy(pNew->zName, zName, nName+1);
>     for(p=pDb->pFunc; p; p=p->pNext){
> @@ -1168,6 +1176,10 @@
>       nVar = sqlite3_bind_parameter_count(pStmt);
>       nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *);
>       pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte);
> +    if( !pPreStmt ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>       memset(pPreStmt, 0, nByte);
>
>       pPreStmt->pStmt = pStmt;
> @@ -1177,6 +1189,11 @@
>   #ifdef SQLITE_TEST
>       if( pPreStmt->zSql==0 ){
>         char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1);
> +      if( !zCopy ) {
> +    Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +    Tcl_Free(pPreStmt);
> +    return TCL_ERROR;
> +      }
>         memcpy(zCopy, zSql, pPreStmt->nSql);
>         zCopy[pPreStmt->nSql] = '\0';
>         pPreStmt->zSql = zCopy;
> @@ -1372,6 +1389,10 @@
>       p->nCol = nCol = sqlite3_column_count(pStmt);
>       if( nCol>0 && (papColName || p->pArray) ){
>         apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
> +      if( !apColName ){
> +    Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +    return;
> +      }
>         for(i=0; i<nCol; i++){
>           apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1);
>           Tcl_IncrRefCount(apColName[i]);
> @@ -1715,6 +1736,10 @@
>         zAuth = Tcl_GetStringFromObj(objv[2], &len);
>         if( zAuth && len>0 ){
>           pDb->zAuth = Tcl_Alloc( len + 1 );
> +    if( !pDb->zAuth ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>           memcpy(pDb->zAuth, zAuth, len+1);
>         }else{
>           pDb->zAuth = 0;
> @@ -1804,6 +1829,10 @@
>         zBusy = Tcl_GetStringFromObj(objv[2], &len);
>         if( zBusy && len>0 ){
>           pDb->zBusy = Tcl_Alloc( len + 1 );
> +    if( !pDb->zBusy ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>           memcpy(pDb->zBusy, zBusy, len+1);
>         }else{
>           pDb->zBusy = 0;
> @@ -1970,6 +1999,10 @@
>         zCommit = Tcl_GetStringFromObj(objv[2], &len);
>         if( zCommit && len>0 ){
>           pDb->zCommit = Tcl_Alloc( len + 1 );
> +    if( !pDb->zCommit ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>           memcpy(pDb->zCommit, zCommit, len+1);
>         }else{
>           pDb->zCommit = 0;
> @@ -2315,6 +2348,10 @@
>         Tcl_IncrRefCount(pScript);
>
>         p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
> +      if( !p ){
> +    Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +    return TCL_ERROR;
> +      }
>         dbEvalInit(p, pDb, objv[2], pArray);
>
>         cd2[0] = (void *)p;
> @@ -2458,6 +2495,10 @@
>         }
>         if( zNull && len>0 ){
>           pDb->zNull = Tcl_Alloc( len + 1 );
> +    if( !pDb->zNULL ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>           memcpy(pDb->zNull, zNull, len);
>           pDb->zNull[len] = '\0';
>         }else{
> @@ -2513,6 +2554,10 @@
>         zProgress = Tcl_GetStringFromObj(objv[3], &len);
>         if( zProgress && len>0 ){
>           pDb->zProgress = Tcl_Alloc( len + 1 );
> +    if( !pDb->zProgress ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>           memcpy(pDb->zProgress, zProgress, len+1);
>         }else{
>           pDb->zProgress = 0;
> @@ -2555,6 +2600,10 @@
>         zProfile = Tcl_GetStringFromObj(objv[2], &len);
>         if( zProfile && len>0 ){
>           pDb->zProfile = Tcl_Alloc( len + 1 );
> +    if( !pDb->zProfile ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>           memcpy(pDb->zProfile, zProfile, len+1);
>         }else{
>           pDb->zProfile = 0;
> @@ -2741,6 +2790,10 @@
>         zTrace = Tcl_GetStringFromObj(objv[2], &len);
>         if( zTrace && len>0 ){
>           pDb->zTrace = Tcl_Alloc( len + 1 );
> +    if( !pDb->zTrace ){
> +      Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
> +      return TCL_ERROR;
> +    }
>           memcpy(pDb->zTrace, zTrace, len+1);
>         }else{
>           pDb->zTrace = 0;
>
>
> =======================================================================
>
> Here is a test program which shows the potential issue with memcpy()
> and a NULL address location (compiled with: gcc -O2 -Wall -g memcpy.c
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> int main(void)
> {
>      char *buf;
>      int x = 10;
>
>      buf = malloc(80);
> #if 1
>      buf = NULL;    /*    force buf to point to NULL    */
> #endif
>
>      while (0 <-- x)
>          printf("Value of x is: %d\n", x);
>
>      printf("before memcpy() is called...\n");
>      memcpy(buf, "hello", 5);    /* what happens? */
>      printf("after memcpy() is called...\n");
>
>      printf("Address of buf is: %p, value of buf is: %s\n", buf, buf);
>
>      return 0;
> }
>
> Here is the output from 'a.out' (Fedora 22 Server, gcc 5.1)
>
> [bill at moocow ~]$ ./a.out
> Value of x is: 9
> Value of x is: 8
> Value of x is: 7
> Value of x is: 6
> Value of x is: 5
> Value of x is: 4
> Value of x is: 3
> Value of x is: 2
> Value of x is: 1
> before memcpy() is called...
> Segmentation fault (core dumped)
>
> Here is the same program with the buf = NULL statement
> commented out via the pre-processor:
>
> [bill at moocow ~]$ cat memcpy-works.c
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> int main(void)
> {
>      char *buf;
>      int x = 10;
>
>      buf = malloc(80);
> #if 0
>      buf = NULL;    /*    force buf to point to NULL    */
> #endif
>
>      while (0 <-- x)
>          printf("Value of x is: %d\n", x);
>
>      printf("before memcpy() is called...\n");
>      memcpy(buf, "hello", 5);    /* what happens? */
>      printf("after memcpy() is called...\n");
>
>      printf("Address of buf is: %p, value of buf is: %s\n", buf, buf);
>
>      return 0;
> }
>
> Here is the output from ./a.out:
>
> [bill at moocow ~]$ ./a.out
> Value of x is: 9
> Value of x is: 8
> Value of x is: 7
> Value of x is: 6
> Value of x is: 5
> Value of x is: 4
> Value of x is: 3
> Value of x is: 2
> Value of x is: 1
> before memcpy() is called...
> after memcpy() is called...
> Address of buf is: 0x24df010, value of buf is: hello
>
>
> I am attaching the patch file to this bug report...
>
> Questions, Comments, Suggestions, Complaints? :)
>
> Bill Parker (wp02855 at gmail dot com)
>
>
> _______________________________________________
> sqlite-users mailing list
> sqlite-users at mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to