@@ -2566,7 +2566,7 @@ static noinline_for_stack
25662566struct fmt format_decode (struct fmt fmt , struct printf_spec * spec )
25672567{
25682568 const char * start = fmt .str ;
2569- char flag , qualifier ;
2569+ char flag ;
25702570
25712571 /* we finished early by reading the field width */
25722572 if (fmt .state == FORMAT_STATE_WIDTH ) {
@@ -2637,96 +2637,71 @@ struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
26372637 }
26382638
26392639qualifier :
2640- /* get the conversion qualifier */
2641- qualifier = 0 ;
2642- if (* fmt .str == 'h' || _tolower (* fmt .str ) == 'l' ||
2643- * fmt .str == 'z' || * fmt .str == 't' ) {
2644- qualifier = * fmt .str ++ ;
2645- if (unlikely (qualifier == * fmt .str )) {
2646- if (qualifier == 'l' ) {
2647- qualifier = 'L' ;
2648- fmt .str ++ ;
2649- } else if (qualifier == 'h' ) {
2650- qualifier = 'H' ;
2651- fmt .str ++ ;
2652- }
2653- }
2654- }
2655-
2656- /* default base */
2640+ /* Set up default numeric format */
26572641 spec -> base = 10 ;
2658- switch (* fmt .str ) {
2659- case 'c' :
2660- fmt .state = FORMAT_STATE_CHAR ;
2661- fmt .str ++ ;
2662- return fmt ;
2663-
2664- case 's' :
2665- fmt .state = FORMAT_STATE_STR ;
2666- fmt .str ++ ;
2667- return fmt ;
2668-
2669- case 'p' :
2670- fmt .state = FORMAT_STATE_PTR ;
2671- fmt .str ++ ;
2672- return fmt ;
2673-
2674- case '%' :
2675- fmt .state = FORMAT_STATE_PERCENT_CHAR ;
2676- fmt .str ++ ;
2677- return fmt ;
2678-
2679- /* integer number formats - set up the flags and "break" */
2680- case 'o' :
2681- spec -> base = 8 ;
2682- break ;
2683-
2684- case 'x' :
2685- spec -> flags |= SMALL ;
2686- fallthrough ;
2687-
2688- case 'X' :
2689- spec -> base = 16 ;
2690- break ;
2642+ fmt .state = FORMAT_STATE_SIZE (int );
2643+ static const struct format_state {
2644+ unsigned char state ;
2645+ unsigned char flags_or_double_state ;
2646+ unsigned char modifier ;
2647+ unsigned char base ;
2648+ } lookup_state [256 ] = {
2649+ // Qualifiers
2650+ ['l' ] = { FORMAT_STATE_SIZE (long ), FORMAT_STATE_SIZE (long long ), 1 },
2651+ ['L' ] = { FORMAT_STATE_SIZE (long long ), 0 , 1 },
2652+ ['h' ] = { FORMAT_STATE_SIZE (short ), FORMAT_STATE_SIZE (char ), 1 },
2653+ ['H' ] = { FORMAT_STATE_SIZE (char ), 0 , 1 }, // Questionable, historic
2654+ ['z' ] = { FORMAT_STATE_SIZE (size_t ), 0 , 1 },
2655+ ['t' ] = { FORMAT_STATE_SIZE (ptrdiff_t ), 0 , 1 },
2656+
2657+ // Non-numeric formats
2658+ ['c' ] = { FORMAT_STATE_CHAR },
2659+ ['s' ] = { FORMAT_STATE_STR },
2660+ ['p' ] = { FORMAT_STATE_PTR },
2661+ ['%' ] = { FORMAT_STATE_PERCENT_CHAR },
2662+
2663+ // Numerics
2664+ ['o' ] = { 0 , 0 , 0 , 8 },
2665+ ['x' ] = { 0 , SMALL , 0 , 16 },
2666+ ['X' ] = { 0 , 0 , 0 , 16 },
2667+ ['d' ] = { 0 , SIGN , 0 , 10 },
2668+ ['i' ] = { 0 , SIGN , 0 , 10 },
2669+ ['u' ] = { 0 , 0 , 0 , 10 , },
26912670
2692- case 'd' :
2693- case 'i' :
2694- spec -> flags |= SIGN ;
2695- break ;
2696- case 'u' :
2697- break ;
2698-
2699- case 'n' :
27002671 /*
27012672 * Since %n poses a greater security risk than
27022673 * utility, treat it as any other invalid or
27032674 * unsupported format specifier.
27042675 */
2705- fallthrough ;
2676+ } ;
27062677
2707- default :
2708- WARN_ONCE (1 , "Please remove unsupported %%%c in format string\n" , * fmt .str );
2709- fmt .state = FORMAT_STATE_INVALID ;
2678+ const struct format_state * p = lookup_state + (u8 )* fmt .str ;
2679+ if (p -> modifier ) {
2680+ fmt .state = p -> state ;
2681+ if (p -> flags_or_double_state && fmt .str [0 ] == fmt .str [1 ]) {
2682+ fmt .state = p -> flags_or_double_state ;
2683+ fmt .str ++ ;
2684+ }
2685+ fmt .str ++ ;
2686+ p = lookup_state + * fmt .str ;
2687+ if (unlikely (p -> modifier ))
2688+ goto invalid ;
2689+ }
2690+ if (p -> base ) {
2691+ spec -> base = p -> base ;
2692+ spec -> flags |= p -> flags_or_double_state ;
2693+ fmt .str ++ ;
27102694 return fmt ;
27112695 }
2712-
2713- if (qualifier == 'L' )
2714- fmt .state = FORMAT_STATE_SIZE (long long );
2715- else if (qualifier == 'l' ) {
2716- fmt .state = FORMAT_STATE_SIZE (long );
2717- } else if (qualifier == 'z' ) {
2718- fmt .state = FORMAT_STATE_SIZE (size_t );
2719- } else if (qualifier == 't' ) {
2720- fmt .state = FORMAT_STATE_SIZE (ptrdiff_t );
2721- } else if (qualifier == 'H' ) {
2722- fmt .state = FORMAT_STATE_SIZE (char );
2723- } else if (qualifier == 'h' ) {
2724- fmt .state = FORMAT_STATE_SIZE (short );
2725- } else {
2726- fmt .state = FORMAT_STATE_SIZE (int );
2696+ if (p -> state ) {
2697+ fmt .state = p -> state ;
2698+ fmt .str ++ ;
2699+ return fmt ;
27272700 }
27282701
2729- fmt .str ++ ;
2702+ invalid :
2703+ WARN_ONCE (1 , "Please remove unsupported %%%c in format string\n" , * fmt .str );
2704+ fmt .state = FORMAT_STATE_INVALID ;
27302705 return fmt ;
27312706}
27322707
0 commit comments