Fossil SCM
Fix an infinite recursion on db_err() that might occur if SQLite is unable to create the WAL file for a database due to lack of write permission on the containing directory.
Commit
421fe24138cd443b0059bb51baec08f4561a783f6f93ed2ec8ad9a17d2b85f4c
Parent
3f316764921b4ed…
1 file changed
+6
M
src/db.c
+6
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -54,10 +54,11 @@ | ||
| 54 | 54 | struct Stmt { |
| 55 | 55 | Blob sql; /* The SQL for this statement */ |
| 56 | 56 | sqlite3_stmt *pStmt; /* The results of sqlite3_prepare_v2() */ |
| 57 | 57 | Stmt *pNext, *pPrev; /* List of all unfinalized statements */ |
| 58 | 58 | int nStep; /* Number of sqlite3_step() calls */ |
| 59 | + int rc; /* Error from db_vprepare() */ | |
| 59 | 60 | }; |
| 60 | 61 | |
| 61 | 62 | /* |
| 62 | 63 | ** Copy this to initialize a Stmt object to a clean/empty state. This |
| 63 | 64 | ** is useful to help avoid assertions when performing cleanup in some |
| @@ -69,13 +70,15 @@ | ||
| 69 | 70 | |
| 70 | 71 | /* |
| 71 | 72 | ** Call this routine when a database error occurs. |
| 72 | 73 | */ |
| 73 | 74 | static void db_err(const char *zFormat, ...){ |
| 75 | + static int rcLooping = 0; | |
| 74 | 76 | va_list ap; |
| 75 | 77 | char *z; |
| 76 | 78 | int rc = 1; |
| 79 | + if( rcLooping ) exit(rcLooping); | |
| 77 | 80 | va_start(ap, zFormat); |
| 78 | 81 | z = vmprintf(zFormat, ap); |
| 79 | 82 | va_end(ap); |
| 80 | 83 | #ifdef FOSSIL_ENABLE_JSON |
| 81 | 84 | if( g.json.isJsonMode ){ |
| @@ -97,10 +100,11 @@ | ||
| 97 | 100 | cgi_reply(); |
| 98 | 101 | }else{ |
| 99 | 102 | fprintf(stderr, "%s: %s\n", g.argv[0], z); |
| 100 | 103 | } |
| 101 | 104 | free(z); |
| 105 | + rcLooping = rc; | |
| 102 | 106 | db_force_rollback(); |
| 103 | 107 | fossil_exit(rc); |
| 104 | 108 | } |
| 105 | 109 | |
| 106 | 110 | /* |
| @@ -273,10 +277,11 @@ | ||
| 273 | 277 | if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)!=0 ){ |
| 274 | 278 | db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); |
| 275 | 279 | } |
| 276 | 280 | pStmt->pNext = pStmt->pPrev = 0; |
| 277 | 281 | pStmt->nStep = 0; |
| 282 | + pStmt->rc = rc; | |
| 278 | 283 | return rc; |
| 279 | 284 | } |
| 280 | 285 | int db_prepare(Stmt *pStmt, const char *zFormat, ...){ |
| 281 | 286 | int rc; |
| 282 | 287 | va_list ap; |
| @@ -359,10 +364,11 @@ | ||
| 359 | 364 | ** Step the SQL statement. Return either SQLITE_ROW or an error code |
| 360 | 365 | ** or SQLITE_OK if the statement finishes successfully. |
| 361 | 366 | */ |
| 362 | 367 | int db_step(Stmt *pStmt){ |
| 363 | 368 | int rc; |
| 369 | + if( pStmt->pStmt==0 ) return pStmt->rc; | |
| 364 | 370 | rc = sqlite3_step(pStmt->pStmt); |
| 365 | 371 | pStmt->nStep++; |
| 366 | 372 | return rc; |
| 367 | 373 | } |
| 368 | 374 | |
| 369 | 375 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -54,10 +54,11 @@ | |
| 54 | struct Stmt { |
| 55 | Blob sql; /* The SQL for this statement */ |
| 56 | sqlite3_stmt *pStmt; /* The results of sqlite3_prepare_v2() */ |
| 57 | Stmt *pNext, *pPrev; /* List of all unfinalized statements */ |
| 58 | int nStep; /* Number of sqlite3_step() calls */ |
| 59 | }; |
| 60 | |
| 61 | /* |
| 62 | ** Copy this to initialize a Stmt object to a clean/empty state. This |
| 63 | ** is useful to help avoid assertions when performing cleanup in some |
| @@ -69,13 +70,15 @@ | |
| 69 | |
| 70 | /* |
| 71 | ** Call this routine when a database error occurs. |
| 72 | */ |
| 73 | static void db_err(const char *zFormat, ...){ |
| 74 | va_list ap; |
| 75 | char *z; |
| 76 | int rc = 1; |
| 77 | va_start(ap, zFormat); |
| 78 | z = vmprintf(zFormat, ap); |
| 79 | va_end(ap); |
| 80 | #ifdef FOSSIL_ENABLE_JSON |
| 81 | if( g.json.isJsonMode ){ |
| @@ -97,10 +100,11 @@ | |
| 97 | cgi_reply(); |
| 98 | }else{ |
| 99 | fprintf(stderr, "%s: %s\n", g.argv[0], z); |
| 100 | } |
| 101 | free(z); |
| 102 | db_force_rollback(); |
| 103 | fossil_exit(rc); |
| 104 | } |
| 105 | |
| 106 | /* |
| @@ -273,10 +277,11 @@ | |
| 273 | if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)!=0 ){ |
| 274 | db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); |
| 275 | } |
| 276 | pStmt->pNext = pStmt->pPrev = 0; |
| 277 | pStmt->nStep = 0; |
| 278 | return rc; |
| 279 | } |
| 280 | int db_prepare(Stmt *pStmt, const char *zFormat, ...){ |
| 281 | int rc; |
| 282 | va_list ap; |
| @@ -359,10 +364,11 @@ | |
| 359 | ** Step the SQL statement. Return either SQLITE_ROW or an error code |
| 360 | ** or SQLITE_OK if the statement finishes successfully. |
| 361 | */ |
| 362 | int db_step(Stmt *pStmt){ |
| 363 | int rc; |
| 364 | rc = sqlite3_step(pStmt->pStmt); |
| 365 | pStmt->nStep++; |
| 366 | return rc; |
| 367 | } |
| 368 | |
| 369 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -54,10 +54,11 @@ | |
| 54 | struct Stmt { |
| 55 | Blob sql; /* The SQL for this statement */ |
| 56 | sqlite3_stmt *pStmt; /* The results of sqlite3_prepare_v2() */ |
| 57 | Stmt *pNext, *pPrev; /* List of all unfinalized statements */ |
| 58 | int nStep; /* Number of sqlite3_step() calls */ |
| 59 | int rc; /* Error from db_vprepare() */ |
| 60 | }; |
| 61 | |
| 62 | /* |
| 63 | ** Copy this to initialize a Stmt object to a clean/empty state. This |
| 64 | ** is useful to help avoid assertions when performing cleanup in some |
| @@ -69,13 +70,15 @@ | |
| 70 | |
| 71 | /* |
| 72 | ** Call this routine when a database error occurs. |
| 73 | */ |
| 74 | static void db_err(const char *zFormat, ...){ |
| 75 | static int rcLooping = 0; |
| 76 | va_list ap; |
| 77 | char *z; |
| 78 | int rc = 1; |
| 79 | if( rcLooping ) exit(rcLooping); |
| 80 | va_start(ap, zFormat); |
| 81 | z = vmprintf(zFormat, ap); |
| 82 | va_end(ap); |
| 83 | #ifdef FOSSIL_ENABLE_JSON |
| 84 | if( g.json.isJsonMode ){ |
| @@ -97,10 +100,11 @@ | |
| 100 | cgi_reply(); |
| 101 | }else{ |
| 102 | fprintf(stderr, "%s: %s\n", g.argv[0], z); |
| 103 | } |
| 104 | free(z); |
| 105 | rcLooping = rc; |
| 106 | db_force_rollback(); |
| 107 | fossil_exit(rc); |
| 108 | } |
| 109 | |
| 110 | /* |
| @@ -273,10 +277,11 @@ | |
| 277 | if( rc!=0 && (flags & DB_PREPARE_IGNORE_ERROR)!=0 ){ |
| 278 | db_err("%s\n%s", sqlite3_errmsg(g.db), zSql); |
| 279 | } |
| 280 | pStmt->pNext = pStmt->pPrev = 0; |
| 281 | pStmt->nStep = 0; |
| 282 | pStmt->rc = rc; |
| 283 | return rc; |
| 284 | } |
| 285 | int db_prepare(Stmt *pStmt, const char *zFormat, ...){ |
| 286 | int rc; |
| 287 | va_list ap; |
| @@ -359,10 +364,11 @@ | |
| 364 | ** Step the SQL statement. Return either SQLITE_ROW or an error code |
| 365 | ** or SQLITE_OK if the statement finishes successfully. |
| 366 | */ |
| 367 | int db_step(Stmt *pStmt){ |
| 368 | int rc; |
| 369 | if( pStmt->pStmt==0 ) return pStmt->rc; |
| 370 | rc = sqlite3_step(pStmt->pStmt); |
| 371 | pStmt->nStep++; |
| 372 | return rc; |
| 373 | } |
| 374 | |
| 375 |