@@ -364,6 +364,27 @@ php_sprintf_getnumber(char **buffer, size_t *len)
364
364
}
365
365
/* }}} */
366
366
367
+ #define ARG_NUM_NEXT -1
368
+ #define ARG_NUM_INVALID -2
369
+
370
+ int php_sprintf_get_argnum (char * * format , size_t * format_len ) {
371
+ char * temppos = * format ;
372
+ while (isdigit ((int ) * temppos )) temppos ++ ;
373
+ if (* temppos != '$' ) {
374
+ return ARG_NUM_NEXT ;
375
+ }
376
+
377
+ int argnum = php_sprintf_getnumber (format , format_len );
378
+ if (argnum <= 0 ) {
379
+ zend_value_error ("Argument number must be greater than zero" );
380
+ return ARG_NUM_INVALID ;
381
+ }
382
+
383
+ (* format )++ ; /* skip the '$' */
384
+ (* format_len )-- ;
385
+ return argnum - 1 ;
386
+ }
387
+
367
388
/* php_formatted_print() {{{
368
389
* New sprintf implementation for PHP.
369
390
*
@@ -438,24 +459,12 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
438
459
* format , format - Z_STRVAL_P (z_format )));
439
460
if (isalpha ((int )* format )) {
440
461
width = precision = 0 ;
441
- argnum = currarg ++ ;
462
+ argnum = ARG_NUM_NEXT ;
442
463
} else {
443
464
/* first look for argnum */
444
- temppos = format ;
445
- while (isdigit ((int )* temppos )) temppos ++ ;
446
- if (* temppos == '$' ) {
447
- argnum = php_sprintf_getnumber (& format , & format_len );
448
-
449
- if (argnum <= 0 ) {
450
- zend_string_efree (result );
451
- zend_value_error ("Argument number must be greater than zero" );
452
- return NULL ;
453
- }
454
- argnum -- ;
455
- format ++ ; /* skip the '$' */
456
- format_len -- ;
457
- } else {
458
- argnum = currarg ++ ;
465
+ argnum = php_sprintf_get_argnum (& format , & format_len );
466
+ if (argnum == ARG_NUM_INVALID ) {
467
+ goto fail ;
459
468
}
460
469
461
470
/* after argnum comes modifiers */
@@ -503,11 +512,38 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
503
512
format ++ ;
504
513
format_len -- ;
505
514
PRINTF_DEBUG (("sprintf: getting precision\n" ));
506
- if (isdigit ((int )* format )) {
515
+ if (* format == '*' ) {
516
+ format ++ ;
517
+ format_len -- ;
518
+
519
+ int prec_argnum = php_sprintf_get_argnum (& format , & format_len );
520
+ if (prec_argnum == ARG_NUM_INVALID ) {
521
+ goto fail ;
522
+ }
523
+ if (prec_argnum == ARG_NUM_NEXT ) {
524
+ prec_argnum = currarg ++ ;
525
+ }
526
+ if (prec_argnum >= argc ) {
527
+ max_missing_argnum = MAX (max_missing_argnum , prec_argnum );
528
+ continue ;
529
+ }
530
+ tmp = & args [prec_argnum ];
531
+ ZVAL_DEREF (tmp );
532
+ if (Z_TYPE_P (tmp ) != IS_LONG ) {
533
+ zend_value_error ("Precision must be an integer" );
534
+ goto fail ;
535
+ }
536
+ if (Z_LVAL_P (tmp ) < -1 || Z_LVAL_P (tmp ) > INT_MAX ) {
537
+ zend_value_error ("Precision must be between -1 and %d" , INT_MAX );
538
+ goto fail ;
539
+ }
540
+ precision = Z_LVAL_P (tmp );
541
+ adjusting |= ADJ_PRECISION ;
542
+ expprec = 1 ;
543
+ } else if (isdigit ((int )* format )) {
507
544
if ((precision = php_sprintf_getnumber (& format , & format_len )) < 0 ) {
508
- efree (result );
509
545
zend_value_error ("Precision must be greater than zero and less than %d" , INT_MAX );
510
- return NULL ;
546
+ goto fail ;
511
547
}
512
548
adjusting |= ADJ_PRECISION ;
513
549
expprec = 1 ;
@@ -526,11 +562,19 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
526
562
}
527
563
PRINTF_DEBUG (("sprintf: format character='%c'\n" , * format ));
528
564
565
+ if (argnum == ARG_NUM_NEXT ) {
566
+ argnum = currarg ++ ;
567
+ }
529
568
if (argnum >= argc ) {
530
569
max_missing_argnum = MAX (max_missing_argnum , argnum );
531
570
continue ;
532
571
}
533
572
573
+ if (expprec && precision == -1 && * format != 'g' && * format != 'G' ) {
574
+ zend_value_error ("Precision -1 is only supported for %%g and %%G" );
575
+ goto fail ;
576
+ }
577
+
534
578
/* now we expect to find a type specifier */
535
579
tmp = & args [argnum ];
536
580
switch (* format ) {
@@ -641,6 +685,10 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
641
685
ZSTR_VAL (result )[outpos ]= 0 ;
642
686
ZSTR_LEN (result ) = outpos ;
643
687
return result ;
688
+
689
+ fail :
690
+ zend_string_efree (result );
691
+ return NULL ;
644
692
}
645
693
/* }}} */
646
694
0 commit comments