@@ -55,9 +55,21 @@ typedef ZEND_SET_ALIGNED(1, unsigned int unaligned_uint);
5555typedef ZEND_SET_ALIGNED (1 , int unaligned_int ) ;
5656
5757/* {{{ php_pack */
58- static void php_pack (const zval * val , size_t size , php_pack_endianness endianness , char * output )
58+ static bool php_pack (
59+ const zval * val , uint32_t arg_num , char format_code , size_t size ,
60+ php_pack_endianness endianness , char * output
61+ )
5962{
60- zend_ulong zl = zval_get_long (val );
63+ bool failed ;
64+ zend_ulong zl = zval_try_get_long (val , & failed );
65+
66+ if (UNEXPECTED (failed )) {
67+ zend_argument_type_error (
68+ arg_num , "must be of type int for format code '%c', %s given" ,
69+ format_code , zend_zval_value_name (val )
70+ );
71+ return false;
72+ }
6173
6274 if ((endianness == PHP_LITTLE_ENDIAN ) != MACHINE_LITTLE_ENDIAN ) {
6375 zl = PHP_LONG_BSWAP (zl );
@@ -71,9 +83,28 @@ static void php_pack(const zval *val, size_t size, php_pack_endianness endiannes
7183 }
7284
7385 memcpy (output , (const char * ) & zl , size );
86+ return true;
7487}
7588/* }}} */
7689
90+ static bool php_pack_try_get_double (
91+ const zval * value , uint32_t arg_num , char format_code , double * result
92+ )
93+ {
94+ bool failed ;
95+
96+ * result = zval_try_get_double (value , & failed );
97+ if (UNEXPECTED (failed )) {
98+ zend_argument_type_error (
99+ arg_num , "must be of type float for format code '%c', %s given" ,
100+ format_code , zend_zval_value_name (value )
101+ );
102+ return false;
103+ }
104+
105+ return true;
106+ }
107+
77108ZEND_ATTRIBUTE_CONST static inline uint16_t php_pack_reverse_int16 (uint16_t arg )
78109{
79110 return ((arg & 0xFF ) << 8 ) | ((arg >> 8 ) & 0xFF );
@@ -211,6 +242,7 @@ PHP_FUNCTION(pack)
211242 size_t formatcount = 0 ;
212243 int outputpos = 0 , outputsize = 0 ;
213244 zend_string * output ;
245+ bool conversion_failed = false;
214246
215247 ZEND_PARSE_PARAMETERS_START (1 , -1 )
216248 Z_PARAM_STRING (format , formatlen )
@@ -614,7 +646,14 @@ PHP_FUNCTION(pack)
614646 case 'c' :
615647 case 'C' :
616648 while (arg -- > 0 ) {
617- php_pack (& argv [currentarg ++ ], 1 , PHP_MACHINE_ENDIAN , & ZSTR_VAL (output )[outputpos ]);
649+ uint32_t arg_num = currentarg + 2 ;
650+ if (!php_pack (
651+ & argv [currentarg ], arg_num , code , 1 , PHP_MACHINE_ENDIAN , & ZSTR_VAL (output )[outputpos ]
652+ )) {
653+ conversion_failed = true;
654+ goto cleanup ;
655+ }
656+ currentarg ++ ;
618657 outputpos ++ ;
619658 }
620659 break ;
@@ -636,7 +675,14 @@ PHP_FUNCTION(pack)
636675 }
637676
638677 while (arg -- > 0 ) {
639- php_pack (& argv [currentarg ++ ], 2 , endianness , & ZSTR_VAL (output )[outputpos ]);
678+ uint32_t arg_num = currentarg + 2 ;
679+ if (!php_pack (
680+ & argv [currentarg ], arg_num , code , 2 , endianness , & ZSTR_VAL (output )[outputpos ]
681+ )) {
682+ conversion_failed = true;
683+ goto cleanup ;
684+ }
685+ currentarg ++ ;
640686 outputpos += 2 ;
641687 }
642688 break ;
@@ -645,7 +691,15 @@ PHP_FUNCTION(pack)
645691 case 'i' :
646692 case 'I' :
647693 while (arg -- > 0 ) {
648- php_pack (& argv [currentarg ++ ], sizeof (int ), PHP_MACHINE_ENDIAN , & ZSTR_VAL (output )[outputpos ]);
694+ uint32_t arg_num = currentarg + 2 ;
695+ if (!php_pack (
696+ & argv [currentarg ], arg_num , code , sizeof (int ), PHP_MACHINE_ENDIAN ,
697+ & ZSTR_VAL (output )[outputpos ]
698+ )) {
699+ conversion_failed = true;
700+ goto cleanup ;
701+ }
702+ currentarg ++ ;
649703 outputpos += sizeof (int );
650704 }
651705 break ;
@@ -667,7 +721,14 @@ PHP_FUNCTION(pack)
667721 }
668722
669723 while (arg -- > 0 ) {
670- php_pack (& argv [currentarg ++ ], 4 , endianness , & ZSTR_VAL (output )[outputpos ]);
724+ uint32_t arg_num = currentarg + 2 ;
725+ if (!php_pack (
726+ & argv [currentarg ], arg_num , code , 4 , endianness , & ZSTR_VAL (output )[outputpos ]
727+ )) {
728+ conversion_failed = true;
729+ goto cleanup ;
730+ }
731+ currentarg ++ ;
671732 outputpos += 4 ;
672733 }
673734 break ;
@@ -691,7 +752,14 @@ PHP_FUNCTION(pack)
691752 }
692753
693754 while (arg -- > 0 ) {
694- php_pack (& argv [currentarg ++ ], 8 , endianness , & ZSTR_VAL (output )[outputpos ]);
755+ uint32_t arg_num = currentarg + 2 ;
756+ if (!php_pack (
757+ & argv [currentarg ], arg_num , code , 8 , endianness , & ZSTR_VAL (output )[outputpos ]
758+ )) {
759+ conversion_failed = true;
760+ goto cleanup ;
761+ }
762+ currentarg ++ ;
695763 outputpos += 8 ;
696764 }
697765 break ;
@@ -702,7 +770,15 @@ PHP_FUNCTION(pack)
702770 case 'g' :
703771 case 'G' : {
704772 while (arg -- > 0 ) {
705- float v = (float ) zval_get_double (& argv [currentarg ++ ]);
773+ double d ;
774+ float v ;
775+ uint32_t arg_num = currentarg + 2 ;
776+ if (!php_pack_try_get_double (& argv [currentarg ], arg_num , code , & d )) {
777+ conversion_failed = true;
778+ goto cleanup ;
779+ }
780+ currentarg ++ ;
781+ v = (float ) d ;
706782 if (code == 'g' || formatendian [i ] == PHP_LITTLE_ENDIAN ) {
707783 php_pack_copy_float (1 , & ZSTR_VAL (output )[outputpos ], v );
708784 } else if (code == 'G' || formatendian [i ] == PHP_BIG_ENDIAN ) {
@@ -719,7 +795,13 @@ PHP_FUNCTION(pack)
719795 case 'e' :
720796 case 'E' : {
721797 while (arg -- > 0 ) {
722- double v = zval_get_double (& argv [currentarg ++ ]);
798+ double v ;
799+ uint32_t arg_num = currentarg + 2 ;
800+ if (!php_pack_try_get_double (& argv [currentarg ], arg_num , code , & v )) {
801+ conversion_failed = true;
802+ goto cleanup ;
803+ }
804+ currentarg ++ ;
723805 if (code == 'e' || formatendian [i ] == PHP_LITTLE_ENDIAN ) {
724806 php_pack_copy_double (1 , & ZSTR_VAL (output )[outputpos ], v );
725807 } else if (code == 'E' || formatendian [i ] == PHP_BIG_ENDIAN ) {
@@ -754,11 +836,17 @@ PHP_FUNCTION(pack)
754836 }
755837 }
756838
839+ ZSTR_VAL (output )[outputpos ] = '\0' ;
840+ ZSTR_LEN (output ) = outputpos ;
841+
842+ cleanup :
757843 efree (formatcodes );
758844 efree (formatargs );
759845 efree (formatendian );
760- ZSTR_VAL (output )[outputpos ] = '\0' ;
761- ZSTR_LEN (output ) = outputpos ;
846+ if (UNEXPECTED (conversion_failed )) {
847+ zend_string_release (output );
848+ RETURN_THROWS ();
849+ }
762850 RETURN_NEW_STR (output );
763851}
764852/* }}} */
0 commit comments