Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Remove all precision and width limits from formatting fields in the sqlite3_mprintf() family of functions. Malloc for space as necessary. The prevents a stack overflow on very large numbers using %f. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
1f843fb383583ee7ef51c13b8a820744 |
User & Date: | drh 2011-10-11 17:54:54.587 |
Context
2011-10-11
| ||
18:18 | Change the behavior of the readonly_shm=1 query parameter so that it never attempts to open the -shm file read/write. (check-in: f136400483 user: drh tags: trunk) | |
17:54 | Remove all precision and width limits from formatting fields in the sqlite3_mprintf() family of functions. Malloc for space as necessary. The prevents a stack overflow on very large numbers using %f. (check-in: 1f843fb383 user: drh tags: trunk) | |
12:39 | Fix requirements marks associate with STAT3. (check-in: 9325c1a8c4 user: drh tags: trunk) | |
Changes
Changes to src/printf.c.
︙ | ︙ | |||
186 187 188 189 190 191 192 | } /* ** On machines with a small stack size, you can redefine the ** SQLITE_PRINT_BUF_SIZE to be less than 350. */ #ifndef SQLITE_PRINT_BUF_SIZE | < | < < < | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | } /* ** On machines with a small stack size, you can redefine the ** SQLITE_PRINT_BUF_SIZE to be less than 350. */ #ifndef SQLITE_PRINT_BUF_SIZE # define SQLITE_PRINT_BUF_SIZE 70 #endif #define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */ /* ** The root program. All variations call this core. ** ** INPUTS: |
︙ | ︙ | |||
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ etByte done; /* Loop termination flag */ sqlite_uint64 longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ const et_info *infop; /* Pointer to the appropriate info structure */ char buf[etBUFSIZE]; /* Conversion buffer */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ etByte xtype = 0; /* Conversion paradigm */ char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ | > > < | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ etByte done; /* Loop termination flag */ sqlite_uint64 longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ const et_info *infop; /* Pointer to the appropriate info structure */ char buf[etBUFSIZE]; /* Conversion buffer */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ etByte xtype = 0; /* Conversion paradigm */ char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ int nsd; /* Number of significant digits returned */ #endif length = 0; bufpt = 0; for(; (c=(*fmt))!=0; ++fmt){ if( c!='%' ){ |
︙ | ︙ | |||
303 304 305 306 307 308 309 | c = *++fmt; }else{ while( c>='0' && c<='9' ){ width = width*10 + c - '0'; c = *++fmt; } } | < < < | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | c = *++fmt; }else{ while( c>='0' && c<='9' ){ width = width*10 + c - '0'; c = *++fmt; } } /* Get the precision */ if( c=='.' ){ precision = 0; c = *++fmt; if( c=='*' ){ precision = va_arg(ap,int); if( precision<0 ) precision = -precision; |
︙ | ︙ | |||
352 353 354 355 356 357 358 | return; } break; } } zExtra = 0; | < < < < < < | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | return; } break; } } zExtra = 0; /* ** At this point, variables are initialized as follows: ** ** flag_alternateform TRUE if a '#' is present. ** flag_altform2 TRUE if a '!' is present. ** flag_plussign TRUE if a '+' is present. ** flag_leftjustify TRUE if a '-' is present or if the |
︙ | ︙ | |||
422 423 424 425 426 427 428 | } prefix = 0; } if( longvalue==0 ) flag_alternateform = 0; if( flag_zeropad && precision<width-(prefix!=0) ){ precision = width-(prefix!=0); } | > | > > > > > > > > > > < | | | | < | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 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 | } prefix = 0; } if( longvalue==0 ) flag_alternateform = 0; if( flag_zeropad && precision<width-(prefix!=0) ){ precision = width-(prefix!=0); } if( precision<etBUFSIZE-10 ){ nOut = etBUFSIZE; zOut = buf; }else{ nOut = precision + 10; zOut = zExtra = sqlite3Malloc( nOut ); if( zOut==0 ){ pAccum->mallocFailed = 1; return; } } bufpt = &zOut[nOut-1]; if( xtype==etORDINAL ){ static const char zOrd[] = "thstndrd"; int x = (int)(longvalue % 10); if( x>=4 || (longvalue/10)%10==1 ){ x = 0; } *(--bufpt) = zOrd[x*2+1]; *(--bufpt) = zOrd[x*2]; } { register const char *cset; /* Use registers for speed */ register int base; cset = &aDigits[infop->charset]; base = infop->base; do{ /* Convert to ascii */ *(--bufpt) = cset[longvalue%base]; longvalue = longvalue/base; }while( longvalue>0 ); } length = (int)(&zOut[nOut-1]-bufpt); for(idx=precision-length; idx>0; idx--){ *(--bufpt) = '0'; /* Zero pad */ } if( prefix ) *(--bufpt) = prefix; /* Add sign */ if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ const char *pre; char x; pre = &aPrefix[infop->prefix]; for(; (x=(*pre))!=0; pre++) *(--bufpt) = x; } length = (int)(&zOut[nOut-1]-bufpt); break; case etFLOAT: case etEXP: case etGENERIC: realvalue = va_arg(ap,double); #ifdef SQLITE_OMIT_FLOATING_POINT length = 0; #else if( precision<0 ) precision = 6; /* Set default precision */ if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ if( flag_plussign ) prefix = '+'; else if( flag_blanksign ) prefix = ' '; else prefix = 0; |
︙ | ︙ | |||
512 513 514 515 516 517 518 | } } bufpt = buf; /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ | < > > > > > > > > | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 | } } bufpt = buf; /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ if( xtype!=etFLOAT ){ realvalue += rounder; if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } } if( xtype==etGENERIC ){ flag_rtz = !flag_alternateform; if( exp<-4 || exp>precision ){ xtype = etEXP; }else{ precision = precision - exp; xtype = etFLOAT; } }else{ flag_rtz = 0; } if( xtype==etEXP ){ e2 = 0; }else{ e2 = exp; } if( e2+precision+width > etBUFSIZE - 15 ){ bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 ); if( bufpt==0 ){ pAccum->mallocFailed = 1; return; } } zOut = bufpt; nsd = 0; flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if( prefix ){ *(bufpt++) = prefix; } /* Digits prior to the decimal point */ |
︙ | ︙ | |||
564 565 566 567 568 569 570 | /* Significant digits after the decimal point */ while( (precision--)>0 ){ *(bufpt++) = et_getdigit(&realvalue,&nsd); } /* Remove trailing zeros and the "." if no digits follow the "." */ if( flag_rtz && flag_dp ){ while( bufpt[-1]=='0' ) *(--bufpt) = 0; | | | | | | 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | /* Significant digits after the decimal point */ while( (precision--)>0 ){ *(bufpt++) = et_getdigit(&realvalue,&nsd); } /* Remove trailing zeros and the "." if no digits follow the "." */ if( flag_rtz && flag_dp ){ while( bufpt[-1]=='0' ) *(--bufpt) = 0; assert( bufpt>zOut ); if( bufpt[-1]=='.' ){ if( flag_altform2 ){ *(bufpt++) = '0'; }else{ *(--bufpt) = 0; } } } /* Add the "eNNN" suffix */ if( xtype==etEXP ){ *(bufpt++) = aDigits[infop->charset]; if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; }else{ *(bufpt++) = '+'; } if( exp>=100 ){ *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */ exp %= 100; } *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ } *bufpt = 0; /* The converted number is in buf[] and zero terminated. Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions. */ length = (int)(bufpt-zOut); bufpt = zOut; /* Special case: Add leading zeros if the flag_zeropad flag is ** set and we are not left justified */ if( flag_zeropad && !flag_leftjustify && length < width){ int i; int nPad = width - length; for(i=width; i>=nPad; i--){ |
︙ | ︙ | |||
732 733 734 735 736 737 738 | if( flag_leftjustify ){ register int nspace; nspace = width-length; if( nspace>0 ){ appendSpace(pAccum, nspace); } } | < | < | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | if( flag_leftjustify ){ register int nspace; nspace = width-length; if( nspace>0 ){ appendSpace(pAccum, nspace); } } sqlite3_free(zExtra); }/* End for loop over the format string */ } /* End of function */ /* ** Append N bytes of text from z to the StrAccum object. */ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){ |
︙ | ︙ |
Changes to test/printf.test.
︙ | ︙ | |||
3543 3544 3545 3546 3547 3548 3549 | sqlite3_mprintf_str {%d A quoted string: '%.*q'} 1 6 {Hi Y'all} } {1 A quoted string: 'Hi Y''a'} do_test printf-5.1 { set x [sqlite3_mprintf_str {%d %d %100000s} 0 0 {Hello}] string length $x | | | 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 | sqlite3_mprintf_str {%d A quoted string: '%.*q'} 1 6 {Hi Y'all} } {1 A quoted string: 'Hi Y''a'} do_test printf-5.1 { set x [sqlite3_mprintf_str {%d %d %100000s} 0 0 {Hello}] string length $x } {100004} do_test printf-5.2 { sqlite3_mprintf_str {%d %d (%-10.10s) %} -9 -10 {HelloHelloHello} } {-9 -10 (HelloHello) %} do_test printf-6.1 { sqlite3_mprintf_z_test , one two three four five six } {,one,two,three,four,five,six} |
︙ | ︙ |