@@ -419,10 +419,7 @@ static_assert(SMALL == ('a' ^ 'A'));
419419
420420enum format_state {
421421 FORMAT_STATE_NONE , /* Just a string part */
422- FORMAT_STATE_1BYTE = 1 , /* char/short/int are their own sizes */
423- FORMAT_STATE_2BYTE = 2 ,
424- FORMAT_STATE_8BYTE = 3 ,
425- FORMAT_STATE_4BYTE = 4 ,
422+ FORMAT_STATE_NUM ,
426423 FORMAT_STATE_WIDTH ,
427424 FORMAT_STATE_PRECISION ,
428425 FORMAT_STATE_CHAR ,
@@ -432,8 +429,6 @@ enum format_state {
432429 FORMAT_STATE_INVALID ,
433430};
434431
435- #define FORMAT_STATE_SIZE (type ) (sizeof(type) <= 4 ? sizeof(type) : FORMAT_STATE_8BYTE)
436-
437432struct printf_spec {
438433 unsigned char flags ; /* flags to number() */
439434 unsigned char base ; /* number base, 8, 10 or 16 only */
@@ -2523,7 +2518,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
25232518
25242519struct fmt {
25252520 const char * str ;
2526- enum format_state state ;
2521+ unsigned char state ; // enum format_state
2522+ unsigned char size ; // size of numbers
25272523};
25282524
25292525#define SPEC_CHAR (x , flag ) [(x)-32] = flag
@@ -2638,20 +2634,21 @@ struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
26382634qualifier :
26392635 /* Set up default numeric format */
26402636 spec -> base = 10 ;
2641- fmt .state = FORMAT_STATE_SIZE (int );
2637+ fmt .state = FORMAT_STATE_NUM ;
2638+ fmt .size = sizeof (int );
26422639 static const struct format_state {
26432640 unsigned char state ;
2644- unsigned char flags_or_double_state ;
2645- unsigned char modifier ;
2641+ unsigned char size ;
2642+ unsigned char flags_or_double_size ;
26462643 unsigned char base ;
26472644 } lookup_state [256 ] = {
2648- // Qualifiers
2649- ['l' ] = { FORMAT_STATE_SIZE (long ), FORMAT_STATE_SIZE (long long ), 1 },
2650- ['L' ] = { FORMAT_STATE_SIZE (long long ), 0 , 1 },
2651- ['h' ] = { FORMAT_STATE_SIZE (short ), FORMAT_STATE_SIZE (char ), 1 },
2652- ['H' ] = { FORMAT_STATE_SIZE (char ), 0 , 1 }, // Questionable, historic
2653- ['z' ] = { FORMAT_STATE_SIZE ( size_t ), 0 , 1 },
2654- ['t' ] = { FORMAT_STATE_SIZE ( ptrdiff_t ), 0 , 1 },
2645+ // Length
2646+ ['l' ] = { 0 , sizeof (long ), sizeof (long long ) },
2647+ ['L' ] = { 0 , sizeof (long long ) },
2648+ ['h' ] = { 0 , sizeof (short ), sizeof (char ) },
2649+ ['H' ] = { 0 , sizeof (char ) }, // Questionable historical
2650+ ['z' ] = { 0 , sizeof ( size_t ) },
2651+ ['t' ] = { 0 , sizeof ( ptrdiff_t ) },
26552652
26562653 // Non-numeric formats
26572654 ['c' ] = { FORMAT_STATE_CHAR },
@@ -2660,12 +2657,12 @@ struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
26602657 ['%' ] = { FORMAT_STATE_PERCENT_CHAR },
26612658
26622659 // Numerics
2663- ['o' ] = { 0 , 0 , 0 , 8 },
2664- ['x' ] = { 0 , SMALL , 0 , 16 },
2665- ['X' ] = { 0 , 0 , 0 , 16 },
2666- ['d' ] = { 0 , SIGN , 0 , 10 },
2667- ['i' ] = { 0 , SIGN , 0 , 10 },
2668- ['u' ] = { 0 , 0 , 0 , 10 , },
2660+ ['o' ] = { FORMAT_STATE_NUM , 0 , 0 , 8 },
2661+ ['x' ] = { FORMAT_STATE_NUM , 0 , SMALL , 16 },
2662+ ['X' ] = { FORMAT_STATE_NUM , 0 , 0 , 16 },
2663+ ['d' ] = { FORMAT_STATE_NUM , 0 , SIGN , 10 },
2664+ ['i' ] = { FORMAT_STATE_NUM , 0 , SIGN , 10 },
2665+ ['u' ] = { FORMAT_STATE_NUM , 0 , 0 , 10 , },
26692666
26702667 /*
26712668 * Since %n poses a greater security risk than
@@ -2675,30 +2672,23 @@ struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
26752672 };
26762673
26772674 const struct format_state * p = lookup_state + (u8 )* fmt .str ;
2678- if (p -> modifier ) {
2679- fmt .state = p -> state ;
2680- if (p -> flags_or_double_state && fmt .str [0 ] == fmt .str [1 ]) {
2681- fmt .state = p -> flags_or_double_state ;
2675+ if (p -> size ) {
2676+ fmt .size = p -> size ;
2677+ if (p -> flags_or_double_size && fmt .str [0 ] == fmt .str [1 ]) {
2678+ fmt .size = p -> flags_or_double_size ;
26822679 fmt .str ++ ;
26832680 }
26842681 fmt .str ++ ;
26852682 p = lookup_state + * fmt .str ;
2686- if (unlikely (p -> modifier ))
2687- goto invalid ;
2688- }
2689- if (p -> base ) {
2690- spec -> base = p -> base ;
2691- spec -> flags |= p -> flags_or_double_state ;
2692- fmt .str ++ ;
2693- return fmt ;
26942683 }
26952684 if (p -> state ) {
2685+ spec -> base = p -> base ;
2686+ spec -> flags |= p -> flags_or_double_size ;
26962687 fmt .state = p -> state ;
26972688 fmt .str ++ ;
26982689 return fmt ;
26992690 }
27002691
2701- invalid :
27022692 WARN_ONCE (1 , "Please remove unsupported %%%c in format string\n" , * fmt .str );
27032693 fmt .state = FORMAT_STATE_INVALID ;
27042694 return fmt ;
@@ -2768,7 +2758,6 @@ static unsigned long long convert_num_spec(unsigned int val, int size, struct pr
27682758 */
27692759int vsnprintf (char * buf , size_t size , const char * fmt_str , va_list args )
27702760{
2771- unsigned long long num ;
27722761 char * str , * end ;
27732762 struct printf_spec spec = {0 };
27742763 struct fmt fmt = {
@@ -2808,6 +2797,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt_str, va_list args)
28082797 continue ;
28092798 }
28102799
2800+ case FORMAT_STATE_NUM : {
2801+ unsigned long long num ;
2802+ if (fmt .size <= sizeof (int ))
2803+ num = convert_num_spec (va_arg (args , int ), fmt .size , spec );
2804+ else
2805+ num = va_arg (args , long long );
2806+ str = number (str , end , num , spec );
2807+ continue ;
2808+ }
2809+
28112810 case FORMAT_STATE_WIDTH :
28122811 set_field_width (& spec , va_arg (args , int ));
28132812 continue ;
@@ -2856,7 +2855,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt_str, va_list args)
28562855 ++ str ;
28572856 continue ;
28582857
2859- case FORMAT_STATE_INVALID :
2858+ default :
28602859 /*
28612860 * Presumably the arguments passed gcc's type
28622861 * checking, but there is no safe or sane way
@@ -2866,17 +2865,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt_str, va_list args)
28662865 * sync.
28672866 */
28682867 goto out ;
2869-
2870- case FORMAT_STATE_8BYTE :
2871- num = va_arg (args , long long );
2872- break ;
2873-
2874- default :
2875- num = convert_num_spec (va_arg (args , int ), fmt .state , spec );
2876- break ;
28772868 }
2878-
2879- str = number (str , end , num , spec );
28802869 }
28812870
28822871out :
@@ -3147,17 +3136,20 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt_str, va_list args)
31473136 fmt .str ++ ;
31483137 break ;
31493138
3150- case FORMAT_STATE_8BYTE :
3151- save_arg (long long ) ;
3152- break ;
3153- case FORMAT_STATE_1BYTE :
3154- save_arg (char );
3155- break ;
3156- case FORMAT_STATE_2BYTE :
3157- save_arg (short );
3158- break ;
3159- default :
3160- save_arg (int );
3139+ case FORMAT_STATE_NUM :
3140+ switch (fmt .size ) {
3141+ case 8 :
3142+ save_arg (long long ) ;
3143+ break ;
3144+ case 1 :
3145+ save_arg (char );
3146+ break ;
3147+ case 2 :
3148+ save_arg (short );
3149+ break ;
3150+ default :
3151+ save_arg (int );
3152+ }
31613153 }
31623154 }
31633155
@@ -3325,18 +3317,21 @@ int bstr_printf(char *buf, size_t size, const char *fmt_str, const u32 *bin_buf)
33253317 case FORMAT_STATE_INVALID :
33263318 goto out ;
33273319
3328- case FORMAT_STATE_8BYTE :
3329- num = get_arg (long long );
3330- break ;
3331- case FORMAT_STATE_2BYTE :
3332- num = convert_num_spec (get_arg (short ), fmt .state , spec );
3333- break ;
3334- case FORMAT_STATE_1BYTE :
3335- num = convert_num_spec (get_arg (char ), fmt .state , spec );
3336- break ;
3337- default :
3338- num = convert_num_spec (get_arg (int ), fmt .state , spec );
3339- break ;
3320+ case FORMAT_STATE_NUM :
3321+ switch (fmt .size ) {
3322+ case 8 :
3323+ num = get_arg (long long );
3324+ break ;
3325+ case 1 :
3326+ num = convert_num_spec (get_arg (char ), fmt .size , spec );
3327+ break ;
3328+ case 2 :
3329+ num = convert_num_spec (get_arg (short ), fmt .size , spec );
3330+ break ;
3331+ default :
3332+ num = convert_num_spec (get_arg (int ), fmt .size , spec );
3333+ break ;
3334+ }
33403335 }
33413336
33423337 str = number (str , end , num , spec );
0 commit comments