Fossil SCM

Merge improved Blob overflow defensive code from trunk.

drh 2026-07-25 10:45 UTC http1-1-chunked merge
Commit 109a5e1a0432c0d1de703e4709ee4a507427af6da72c974d86ddf73aa8669cdb
1 file changed +66 -38
+66 -38
--- src/blob.c
+++ src/blob.c
@@ -35,11 +35,11 @@
3535
unsigned int nUsed; /* Number of bytes used in aData[] */
3636
unsigned int nAlloc; /* Number of bytes allocated for aData[] */
3737
unsigned int iCursor; /* Next character of input to parse */
3838
unsigned int blobFlags; /* One or more BLOBFLAG_* bits */
3939
char *aData; /* Where the information is stored */
40
- void (*xRealloc)(Blob*, unsigned int); /* Function to reallocate the buffer */
40
+ void (*xRealloc)(Blob*,u64); /* Function to reallocate the buffer */
4141
};
4242
4343
/*
4444
** Allowed values for Blob.blobFlags
4545
*/
@@ -190,11 +190,11 @@
190190
191191
/*
192192
** If n >= MAX_BLOB_SIZE, calls blob_panic(),
193193
** else this is a no-op.
194194
*/
195
-static void blob_assert_safe_size(i64 n){
195
+static void blob_assert_safe_size(u64 n){
196196
if( n>=(i64)MAX_BLOB_SIZE ){
197197
blob_panic();
198198
}
199199
}
200200
@@ -205,24 +205,24 @@
205205
**
206206
** No attempt is made to recover from an out-of-memory error.
207207
** If an OOM error occurs, an error message is printed on stderr
208208
** and the program exits.
209209
*/
210
-void blobReallocMalloc(Blob *pBlob, unsigned int newSize){
210
+void blobReallocMalloc(Blob *pBlob, u64 newSize){
211211
if( newSize==0 ){
212212
free(pBlob->aData);
213213
pBlob->aData = 0;
214214
pBlob->nAlloc = 0;
215215
pBlob->nUsed = 0;
216216
pBlob->iCursor = 0;
217217
pBlob->blobFlags = 0;
218218
}else if( newSize>pBlob->nAlloc || newSize+4000<pBlob->nAlloc ){
219219
char *pNew;
220
- blob_assert_safe_size((i64)newSize);
220
+ blob_assert_safe_size(newSize);
221221
pNew = fossil_realloc(pBlob->aData, newSize);
222222
pBlob->aData = pNew;
223
- pBlob->nAlloc = newSize;
223
+ pBlob->nAlloc = (unsigned int)newSize;
224224
if( pBlob->nUsed>pBlob->nAlloc ){
225225
pBlob->nUsed = pBlob->nAlloc;
226226
}
227227
}
228228
}
@@ -237,22 +237,22 @@
237237
238238
/*
239239
** A reallocation function for when the initial string is in unmanaged
240240
** space. Copy the string to memory obtained from malloc().
241241
*/
242
-static void blobReallocStatic(Blob *pBlob, unsigned int newSize){
242
+static void blobReallocStatic(Blob *pBlob, u64 newSize){
243243
if( newSize==0 ){
244244
*pBlob = empty_blob;
245245
}else{
246246
char *pNew;
247
- blob_assert_safe_size((i64)newSize);
247
+ blob_assert_safe_size(newSize);
248248
pNew = fossil_malloc( newSize );
249249
if( pBlob->nUsed>newSize ) pBlob->nUsed = newSize;
250250
memcpy(pNew, pBlob->aData, pBlob->nUsed);
251251
pBlob->aData = pNew;
252252
pBlob->xRealloc = blobReallocMalloc;
253
- pBlob->nAlloc = newSize;
253
+ pBlob->nAlloc = (unsigned int)newSize;
254254
}
255255
}
256256
257257
/*
258258
** Reset a blob to be an empty container.
@@ -335,11 +335,11 @@
335335
** routine is faster, but blob_append_full() handles all the corner cases.
336336
** The blob_append() routine automatically calls blob_append_full() if
337337
** necessary.
338338
*/
339339
static void blob_append_full(Blob *pBlob, const char *aData, int nData){
340
- sqlite3_int64 nNew;
340
+ u64 nNew;
341341
/* assert( aData!=0 || nData==0 ); // omitted for speed */
342342
/* blob_is_init(pBlob); // omitted for speed */
343343
if( nData<0 ) nData = strlen(aData);
344344
if( nData==0 ) return;
345345
if( pBlob==0 ){
@@ -364,11 +364,11 @@
364364
memcpy(&pBlob->aData[pBlob->nUsed], aData, nData);
365365
pBlob->nUsed += nData;
366366
pBlob->aData[pBlob->nUsed] = 0; /* Blobs are always nul-terminated */
367367
}
368368
void blob_append(Blob *pBlob, const char *aData, int nData){
369
- sqlite3_int64 nUsed;
369
+ u64 nUsed;
370370
/* assert( aData!=0 || nData==0 ); // omitted for speed */
371371
if( nData<=0 || pBlob==0 || pBlob->nUsed + nData >= pBlob->nAlloc ){
372372
blob_append_full(pBlob, aData, nData);
373373
return;
374374
}
@@ -414,12 +414,12 @@
414414
** Write into pOut, a string literal representation for the first n bytes
415415
** of z[]. The string literal representation is compatible with C, TCL,
416416
** and JSON. Double-quotes are added to both ends. Double-quote and
417417
** backslash characters are escaped.
418418
*/
419
-void blob_append_tcl_literal(Blob *pOut, const char *z, int n){
420
- int i;
419
+void blob_append_tcl_literal(Blob *pOut, const char *z, size_t n){
420
+ size_t i;
421421
blob_append_char(pOut, '"');
422422
for(i=0; i<n; i++){
423423
char c = z[i];
424424
switch( c ){
425425
case '\r': c = 'r';
@@ -433,12 +433,12 @@
433433
blob_append_char(pOut, c);
434434
}
435435
}
436436
blob_append_char(pOut, '"');
437437
}
438
-void blob_append_json_literal(Blob *pOut, const char *z, int n){
439
- int i;
438
+void blob_append_json_literal(Blob *pOut, const char *z, size_t n){
439
+ size_t i;
440440
blob_append_char(pOut, '"');
441441
for(i=0; i<n; i++){
442442
char c = z[i];
443443
switch( c ){
444444
case 0x00:
@@ -615,11 +615,11 @@
615615
616616
/*
617617
** Attempt to resize a blob so that its internal buffer is
618618
** nByte in size. The blob is truncated if necessary.
619619
*/
620
-void blob_resize(Blob *pBlob, unsigned int newSize){
620
+void blob_resize(Blob *pBlob, u64 newSize){
621621
pBlob->xRealloc(pBlob, newSize+1);
622622
pBlob->nUsed = newSize;
623623
pBlob->aData[newSize] = 0;
624624
}
625625
@@ -636,12 +636,12 @@
636636
** We've had at least one report:
637637
** https://fossil-scm.org/forum/forumpost/b7bbd28db4
638638
** which implies that this is unconditionally failing on mingw 32-bit
639639
** builds.
640640
*/
641
-void blob_reserve(Blob *pBlob, unsigned int newSize){
642
- blob_assert_safe_size( (i64)newSize );
641
+void blob_reserve(Blob *pBlob, u64 newSize){
642
+ blob_assert_safe_size( newSize );
643643
if(newSize>pBlob->nAlloc){
644644
pBlob->xRealloc(pBlob, newSize+1);
645645
pBlob->aData[newSize] = 0;
646646
}
647647
}
@@ -652,11 +652,10 @@
652652
*/
653653
char *blob_materialize(Blob *pBlob){
654654
blob_resize(pBlob, pBlob->nUsed);
655655
return pBlob->aData;
656656
}
657
-
658657
659658
/*
660659
** Call dehttpize on a blob. This causes an ephemeral blob to be
661660
** materialized.
662661
*/
@@ -1049,47 +1048,76 @@
10491048
int blob_is_filename(Blob *pBlob){
10501049
return file_is_simple_pathname(blob_str(pBlob), 1);
10511050
}
10521051
10531052
/*
1054
-** Return true if the blob contains a valid 32-bit integer. Store
1055
-** the integer value in *pValue.
1053
+** Return true if the blob contains a valid non-negative 32-bit integer
1054
+** and store the integer value in *pValue. If the blob is not a valid
1055
+** non-negative 32-bit integer, return false and leave *pValue unchanged.
10561056
*/
10571057
int blob_is_int(Blob *pBlob, int *pValue){
10581058
const char *z = blob_buffer(pBlob);
1059
- int i, n, c, v;
1059
+ int i, n, c;
1060
+ sqlite3_uint64 v;
10601061
n = blob_size(pBlob);
10611062
v = 0;
10621063
for(i=0; i<n && (c = z[i])!=0 && c>='0' && c<='9'; i++){
10631064
v = v*10 + c - '0';
1065
+ if( v>0x7fffffff ) return 0;
1066
+ }
1067
+ if( i==n ){
1068
+ *pValue = (int)v;
1069
+ return 1;
1070
+ }else{
1071
+ return 0;
1072
+ }
1073
+}
1074
+
1075
+/*
1076
+** Return true if the blob contains a valid non-negative 64-bit integer
1077
+** and store the integer value in *pValue. If the blob is not a valid
1078
+** non-negative 64-bit integer, return false and leave *pValue unchanged.
1079
+*/
1080
+int blob_is_int64(Blob *pBlob, sqlite3_int64 *pValue){
1081
+ const char *z = blob_buffer(pBlob);
1082
+ int i, n, c;
1083
+ sqlite3_uint64 v;
1084
+ n = blob_size(pBlob);
1085
+ v = 0;
1086
+ for(i=0; i<n && (c = z[i])!=0 && c>='0' && c<='9'; i++){
1087
+ if( v<922337203685477580ULL || (v==922337203685477580ULL && c<='7') ){
1088
+ v = v*10 + c - '0';
1089
+ }else{
1090
+ return 0;
1091
+ }
10641092
}
10651093
if( i==n ){
1066
- *pValue = v;
1094
+ *pValue = (sqlite3_int64)v;
10671095
return 1;
10681096
}else{
10691097
return 0;
10701098
}
10711099
}
10721100
10731101
/*
1074
-** Return true if the blob contains a valid 64-bit integer. Store
1075
-** the integer value in *pValue.
1102
+** COMMAND: test-atoi
1103
+**
1104
+** Use the blob_is_int() and blob_is_int64() routines to convert arguments
1105
+** into integers. Used for unit testing of those routines.
10761106
*/
1077
-int blob_is_int64(Blob *pBlob, sqlite3_int64 *pValue){
1078
- const char *z = blob_buffer(pBlob);
1079
- int i, n, c;
1080
- sqlite3_int64 v;
1081
- n = blob_size(pBlob);
1082
- v = 0;
1083
- for(i=0; i<n && (c = z[i])!=0 && c>='0' && c<='9'; i++){
1084
- v = v*10 + c - '0';
1085
- }
1086
- if( i==n ){
1087
- *pValue = v;
1088
- return 1;
1089
- }else{
1090
- return 0;
1107
+void blob_is_int_cmd(void){
1108
+ int i;
1109
+ for(i=2; i<g.argc; i++){
1110
+ Blob x;
1111
+ int i32 = 0;
1112
+ sqlite3_int64 i64 = 0;
1113
+ int rc;
1114
+ blob_init(&x, g.argv[i], -1);
1115
+ rc = blob_is_int(&x, &i32);
1116
+ fossil_print("%20s: 32-bit %d %-10d", g.argv[i], rc, i32);
1117
+ rc = blob_is_int64(&x, &i64);
1118
+ fossil_print(" 64-bit %d %lld\n", rc, i64);
10911119
}
10921120
}
10931121
10941122
/*
10951123
** Zero or reset an array of Blobs.
10961124
--- src/blob.c
+++ src/blob.c
@@ -35,11 +35,11 @@
35 unsigned int nUsed; /* Number of bytes used in aData[] */
36 unsigned int nAlloc; /* Number of bytes allocated for aData[] */
37 unsigned int iCursor; /* Next character of input to parse */
38 unsigned int blobFlags; /* One or more BLOBFLAG_* bits */
39 char *aData; /* Where the information is stored */
40 void (*xRealloc)(Blob*, unsigned int); /* Function to reallocate the buffer */
41 };
42
43 /*
44 ** Allowed values for Blob.blobFlags
45 */
@@ -190,11 +190,11 @@
190
191 /*
192 ** If n >= MAX_BLOB_SIZE, calls blob_panic(),
193 ** else this is a no-op.
194 */
195 static void blob_assert_safe_size(i64 n){
196 if( n>=(i64)MAX_BLOB_SIZE ){
197 blob_panic();
198 }
199 }
200
@@ -205,24 +205,24 @@
205 **
206 ** No attempt is made to recover from an out-of-memory error.
207 ** If an OOM error occurs, an error message is printed on stderr
208 ** and the program exits.
209 */
210 void blobReallocMalloc(Blob *pBlob, unsigned int newSize){
211 if( newSize==0 ){
212 free(pBlob->aData);
213 pBlob->aData = 0;
214 pBlob->nAlloc = 0;
215 pBlob->nUsed = 0;
216 pBlob->iCursor = 0;
217 pBlob->blobFlags = 0;
218 }else if( newSize>pBlob->nAlloc || newSize+4000<pBlob->nAlloc ){
219 char *pNew;
220 blob_assert_safe_size((i64)newSize);
221 pNew = fossil_realloc(pBlob->aData, newSize);
222 pBlob->aData = pNew;
223 pBlob->nAlloc = newSize;
224 if( pBlob->nUsed>pBlob->nAlloc ){
225 pBlob->nUsed = pBlob->nAlloc;
226 }
227 }
228 }
@@ -237,22 +237,22 @@
237
238 /*
239 ** A reallocation function for when the initial string is in unmanaged
240 ** space. Copy the string to memory obtained from malloc().
241 */
242 static void blobReallocStatic(Blob *pBlob, unsigned int newSize){
243 if( newSize==0 ){
244 *pBlob = empty_blob;
245 }else{
246 char *pNew;
247 blob_assert_safe_size((i64)newSize);
248 pNew = fossil_malloc( newSize );
249 if( pBlob->nUsed>newSize ) pBlob->nUsed = newSize;
250 memcpy(pNew, pBlob->aData, pBlob->nUsed);
251 pBlob->aData = pNew;
252 pBlob->xRealloc = blobReallocMalloc;
253 pBlob->nAlloc = newSize;
254 }
255 }
256
257 /*
258 ** Reset a blob to be an empty container.
@@ -335,11 +335,11 @@
335 ** routine is faster, but blob_append_full() handles all the corner cases.
336 ** The blob_append() routine automatically calls blob_append_full() if
337 ** necessary.
338 */
339 static void blob_append_full(Blob *pBlob, const char *aData, int nData){
340 sqlite3_int64 nNew;
341 /* assert( aData!=0 || nData==0 ); // omitted for speed */
342 /* blob_is_init(pBlob); // omitted for speed */
343 if( nData<0 ) nData = strlen(aData);
344 if( nData==0 ) return;
345 if( pBlob==0 ){
@@ -364,11 +364,11 @@
364 memcpy(&pBlob->aData[pBlob->nUsed], aData, nData);
365 pBlob->nUsed += nData;
366 pBlob->aData[pBlob->nUsed] = 0; /* Blobs are always nul-terminated */
367 }
368 void blob_append(Blob *pBlob, const char *aData, int nData){
369 sqlite3_int64 nUsed;
370 /* assert( aData!=0 || nData==0 ); // omitted for speed */
371 if( nData<=0 || pBlob==0 || pBlob->nUsed + nData >= pBlob->nAlloc ){
372 blob_append_full(pBlob, aData, nData);
373 return;
374 }
@@ -414,12 +414,12 @@
414 ** Write into pOut, a string literal representation for the first n bytes
415 ** of z[]. The string literal representation is compatible with C, TCL,
416 ** and JSON. Double-quotes are added to both ends. Double-quote and
417 ** backslash characters are escaped.
418 */
419 void blob_append_tcl_literal(Blob *pOut, const char *z, int n){
420 int i;
421 blob_append_char(pOut, '"');
422 for(i=0; i<n; i++){
423 char c = z[i];
424 switch( c ){
425 case '\r': c = 'r';
@@ -433,12 +433,12 @@
433 blob_append_char(pOut, c);
434 }
435 }
436 blob_append_char(pOut, '"');
437 }
438 void blob_append_json_literal(Blob *pOut, const char *z, int n){
439 int i;
440 blob_append_char(pOut, '"');
441 for(i=0; i<n; i++){
442 char c = z[i];
443 switch( c ){
444 case 0x00:
@@ -615,11 +615,11 @@
615
616 /*
617 ** Attempt to resize a blob so that its internal buffer is
618 ** nByte in size. The blob is truncated if necessary.
619 */
620 void blob_resize(Blob *pBlob, unsigned int newSize){
621 pBlob->xRealloc(pBlob, newSize+1);
622 pBlob->nUsed = newSize;
623 pBlob->aData[newSize] = 0;
624 }
625
@@ -636,12 +636,12 @@
636 ** We've had at least one report:
637 ** https://fossil-scm.org/forum/forumpost/b7bbd28db4
638 ** which implies that this is unconditionally failing on mingw 32-bit
639 ** builds.
640 */
641 void blob_reserve(Blob *pBlob, unsigned int newSize){
642 blob_assert_safe_size( (i64)newSize );
643 if(newSize>pBlob->nAlloc){
644 pBlob->xRealloc(pBlob, newSize+1);
645 pBlob->aData[newSize] = 0;
646 }
647 }
@@ -652,11 +652,10 @@
652 */
653 char *blob_materialize(Blob *pBlob){
654 blob_resize(pBlob, pBlob->nUsed);
655 return pBlob->aData;
656 }
657
658
659 /*
660 ** Call dehttpize on a blob. This causes an ephemeral blob to be
661 ** materialized.
662 */
@@ -1049,47 +1048,76 @@
1049 int blob_is_filename(Blob *pBlob){
1050 return file_is_simple_pathname(blob_str(pBlob), 1);
1051 }
1052
1053 /*
1054 ** Return true if the blob contains a valid 32-bit integer. Store
1055 ** the integer value in *pValue.
 
1056 */
1057 int blob_is_int(Blob *pBlob, int *pValue){
1058 const char *z = blob_buffer(pBlob);
1059 int i, n, c, v;
 
1060 n = blob_size(pBlob);
1061 v = 0;
1062 for(i=0; i<n && (c = z[i])!=0 && c>='0' && c<='9'; i++){
1063 v = v*10 + c - '0';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1064 }
1065 if( i==n ){
1066 *pValue = v;
1067 return 1;
1068 }else{
1069 return 0;
1070 }
1071 }
1072
1073 /*
1074 ** Return true if the blob contains a valid 64-bit integer. Store
1075 ** the integer value in *pValue.
 
 
1076 */
1077 int blob_is_int64(Blob *pBlob, sqlite3_int64 *pValue){
1078 const char *z = blob_buffer(pBlob);
1079 int i, n, c;
1080 sqlite3_int64 v;
1081 n = blob_size(pBlob);
1082 v = 0;
1083 for(i=0; i<n && (c = z[i])!=0 && c>='0' && c<='9'; i++){
1084 v = v*10 + c - '0';
1085 }
1086 if( i==n ){
1087 *pValue = v;
1088 return 1;
1089 }else{
1090 return 0;
1091 }
1092 }
1093
1094 /*
1095 ** Zero or reset an array of Blobs.
1096
--- src/blob.c
+++ src/blob.c
@@ -35,11 +35,11 @@
35 unsigned int nUsed; /* Number of bytes used in aData[] */
36 unsigned int nAlloc; /* Number of bytes allocated for aData[] */
37 unsigned int iCursor; /* Next character of input to parse */
38 unsigned int blobFlags; /* One or more BLOBFLAG_* bits */
39 char *aData; /* Where the information is stored */
40 void (*xRealloc)(Blob*,u64); /* Function to reallocate the buffer */
41 };
42
43 /*
44 ** Allowed values for Blob.blobFlags
45 */
@@ -190,11 +190,11 @@
190
191 /*
192 ** If n >= MAX_BLOB_SIZE, calls blob_panic(),
193 ** else this is a no-op.
194 */
195 static void blob_assert_safe_size(u64 n){
196 if( n>=(i64)MAX_BLOB_SIZE ){
197 blob_panic();
198 }
199 }
200
@@ -205,24 +205,24 @@
205 **
206 ** No attempt is made to recover from an out-of-memory error.
207 ** If an OOM error occurs, an error message is printed on stderr
208 ** and the program exits.
209 */
210 void blobReallocMalloc(Blob *pBlob, u64 newSize){
211 if( newSize==0 ){
212 free(pBlob->aData);
213 pBlob->aData = 0;
214 pBlob->nAlloc = 0;
215 pBlob->nUsed = 0;
216 pBlob->iCursor = 0;
217 pBlob->blobFlags = 0;
218 }else if( newSize>pBlob->nAlloc || newSize+4000<pBlob->nAlloc ){
219 char *pNew;
220 blob_assert_safe_size(newSize);
221 pNew = fossil_realloc(pBlob->aData, newSize);
222 pBlob->aData = pNew;
223 pBlob->nAlloc = (unsigned int)newSize;
224 if( pBlob->nUsed>pBlob->nAlloc ){
225 pBlob->nUsed = pBlob->nAlloc;
226 }
227 }
228 }
@@ -237,22 +237,22 @@
237
238 /*
239 ** A reallocation function for when the initial string is in unmanaged
240 ** space. Copy the string to memory obtained from malloc().
241 */
242 static void blobReallocStatic(Blob *pBlob, u64 newSize){
243 if( newSize==0 ){
244 *pBlob = empty_blob;
245 }else{
246 char *pNew;
247 blob_assert_safe_size(newSize);
248 pNew = fossil_malloc( newSize );
249 if( pBlob->nUsed>newSize ) pBlob->nUsed = newSize;
250 memcpy(pNew, pBlob->aData, pBlob->nUsed);
251 pBlob->aData = pNew;
252 pBlob->xRealloc = blobReallocMalloc;
253 pBlob->nAlloc = (unsigned int)newSize;
254 }
255 }
256
257 /*
258 ** Reset a blob to be an empty container.
@@ -335,11 +335,11 @@
335 ** routine is faster, but blob_append_full() handles all the corner cases.
336 ** The blob_append() routine automatically calls blob_append_full() if
337 ** necessary.
338 */
339 static void blob_append_full(Blob *pBlob, const char *aData, int nData){
340 u64 nNew;
341 /* assert( aData!=0 || nData==0 ); // omitted for speed */
342 /* blob_is_init(pBlob); // omitted for speed */
343 if( nData<0 ) nData = strlen(aData);
344 if( nData==0 ) return;
345 if( pBlob==0 ){
@@ -364,11 +364,11 @@
364 memcpy(&pBlob->aData[pBlob->nUsed], aData, nData);
365 pBlob->nUsed += nData;
366 pBlob->aData[pBlob->nUsed] = 0; /* Blobs are always nul-terminated */
367 }
368 void blob_append(Blob *pBlob, const char *aData, int nData){
369 u64 nUsed;
370 /* assert( aData!=0 || nData==0 ); // omitted for speed */
371 if( nData<=0 || pBlob==0 || pBlob->nUsed + nData >= pBlob->nAlloc ){
372 blob_append_full(pBlob, aData, nData);
373 return;
374 }
@@ -414,12 +414,12 @@
414 ** Write into pOut, a string literal representation for the first n bytes
415 ** of z[]. The string literal representation is compatible with C, TCL,
416 ** and JSON. Double-quotes are added to both ends. Double-quote and
417 ** backslash characters are escaped.
418 */
419 void blob_append_tcl_literal(Blob *pOut, const char *z, size_t n){
420 size_t i;
421 blob_append_char(pOut, '"');
422 for(i=0; i<n; i++){
423 char c = z[i];
424 switch( c ){
425 case '\r': c = 'r';
@@ -433,12 +433,12 @@
433 blob_append_char(pOut, c);
434 }
435 }
436 blob_append_char(pOut, '"');
437 }
438 void blob_append_json_literal(Blob *pOut, const char *z, size_t n){
439 size_t i;
440 blob_append_char(pOut, '"');
441 for(i=0; i<n; i++){
442 char c = z[i];
443 switch( c ){
444 case 0x00:
@@ -615,11 +615,11 @@
615
616 /*
617 ** Attempt to resize a blob so that its internal buffer is
618 ** nByte in size. The blob is truncated if necessary.
619 */
620 void blob_resize(Blob *pBlob, u64 newSize){
621 pBlob->xRealloc(pBlob, newSize+1);
622 pBlob->nUsed = newSize;
623 pBlob->aData[newSize] = 0;
624 }
625
@@ -636,12 +636,12 @@
636 ** We've had at least one report:
637 ** https://fossil-scm.org/forum/forumpost/b7bbd28db4
638 ** which implies that this is unconditionally failing on mingw 32-bit
639 ** builds.
640 */
641 void blob_reserve(Blob *pBlob, u64 newSize){
642 blob_assert_safe_size( newSize );
643 if(newSize>pBlob->nAlloc){
644 pBlob->xRealloc(pBlob, newSize+1);
645 pBlob->aData[newSize] = 0;
646 }
647 }
@@ -652,11 +652,10 @@
652 */
653 char *blob_materialize(Blob *pBlob){
654 blob_resize(pBlob, pBlob->nUsed);
655 return pBlob->aData;
656 }
 
657
658 /*
659 ** Call dehttpize on a blob. This causes an ephemeral blob to be
660 ** materialized.
661 */
@@ -1049,47 +1048,76 @@
1048 int blob_is_filename(Blob *pBlob){
1049 return file_is_simple_pathname(blob_str(pBlob), 1);
1050 }
1051
1052 /*
1053 ** Return true if the blob contains a valid non-negative 32-bit integer
1054 ** and store the integer value in *pValue. If the blob is not a valid
1055 ** non-negative 32-bit integer, return false and leave *pValue unchanged.
1056 */
1057 int blob_is_int(Blob *pBlob, int *pValue){
1058 const char *z = blob_buffer(pBlob);
1059 int i, n, c;
1060 sqlite3_uint64 v;
1061 n = blob_size(pBlob);
1062 v = 0;
1063 for(i=0; i<n && (c = z[i])!=0 && c>='0' && c<='9'; i++){
1064 v = v*10 + c - '0';
1065 if( v>0x7fffffff ) return 0;
1066 }
1067 if( i==n ){
1068 *pValue = (int)v;
1069 return 1;
1070 }else{
1071 return 0;
1072 }
1073 }
1074
1075 /*
1076 ** Return true if the blob contains a valid non-negative 64-bit integer
1077 ** and store the integer value in *pValue. If the blob is not a valid
1078 ** non-negative 64-bit integer, return false and leave *pValue unchanged.
1079 */
1080 int blob_is_int64(Blob *pBlob, sqlite3_int64 *pValue){
1081 const char *z = blob_buffer(pBlob);
1082 int i, n, c;
1083 sqlite3_uint64 v;
1084 n = blob_size(pBlob);
1085 v = 0;
1086 for(i=0; i<n && (c = z[i])!=0 && c>='0' && c<='9'; i++){
1087 if( v<922337203685477580ULL || (v==922337203685477580ULL && c<='7') ){
1088 v = v*10 + c - '0';
1089 }else{
1090 return 0;
1091 }
1092 }
1093 if( i==n ){
1094 *pValue = (sqlite3_int64)v;
1095 return 1;
1096 }else{
1097 return 0;
1098 }
1099 }
1100
1101 /*
1102 ** COMMAND: test-atoi
1103 **
1104 ** Use the blob_is_int() and blob_is_int64() routines to convert arguments
1105 ** into integers. Used for unit testing of those routines.
1106 */
1107 void blob_is_int_cmd(void){
1108 int i;
1109 for(i=2; i<g.argc; i++){
1110 Blob x;
1111 int i32 = 0;
1112 sqlite3_int64 i64 = 0;
1113 int rc;
1114 blob_init(&x, g.argv[i], -1);
1115 rc = blob_is_int(&x, &i32);
1116 fossil_print("%20s: 32-bit %d %-10d", g.argv[i], rc, i32);
1117 rc = blob_is_int64(&x, &i64);
1118 fossil_print(" 64-bit %d %lld\n", rc, i64);
 
 
1119 }
1120 }
1121
1122 /*
1123 ** Zero or reset an array of Blobs.
1124

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button