@@ -620,44 +620,44 @@ PHP_FUNCTION(pcntl_wstopsig)
620620/* {{{ Executes specified program in current process space as defined by exec(2) */
621621PHP_FUNCTION (pcntl_exec )
622622{
623- zval * args = NULL , * envs = NULL ;
623+ zval * args = NULL ;
624+ HashTable * env_vars_ht = NULL ;
624625 zval * element ;
625- HashTable * args_hash , * envs_hash ;
626- int argc = 0 , argi = 0 ;
627- int envc = 0 , envi = 0 ;
628626 char * * argv = NULL , * * envp = NULL ;
629- char * * current_arg , * * pair ;
630- size_t pair_length ;
631- zend_string * key ;
632627 char * path ;
633628 size_t path_len ;
634- zend_ulong key_num ;
635629
636630 ZEND_PARSE_PARAMETERS_START (1 , 3 )
637631 Z_PARAM_PATH (path , path_len )
638632 Z_PARAM_OPTIONAL
639633 Z_PARAM_ARRAY (args )
640- Z_PARAM_ARRAY ( envs )
634+ Z_PARAM_ARRAY_HT ( env_vars_ht )
641635 ZEND_PARSE_PARAMETERS_END ();
642636
643- if (ZEND_NUM_ARGS () > 1 ) {
637+ if (args != NULL) {
638+ // TODO Check array is a list?
644639 /* Build argument list */
645640 SEPARATE_ARRAY (args );
646- args_hash = Z_ARRVAL_P (args );
647- argc = zend_hash_num_elements (args_hash );
641+ const HashTable * args_ht = Z_ARRVAL_P (args );
642+ uint32_t argc = zend_hash_num_elements (args_ht );
648643
644+ /* We want a NULL terminated array of char* with the first entry being the path,
645+ * followed by the arguments */
649646 argv = safe_emalloc ((argc + 2 ), sizeof (char * ), 0 );
650- * argv = path ;
651- current_arg = argv + 1 ;
652- ZEND_HASH_FOREACH_VAL (args_hash , element ) {
653- if (argi >= argc ) break ;
647+ argv [0 ] = path ;
648+ char * * current_arg = argv + 1 ;
649+ ZEND_HASH_FOREACH_VAL (args_ht , element ) {
654650 if (!try_convert_to_string (element )) {
655651 efree (argv );
656652 RETURN_THROWS ();
657653 }
654+ if (zend_str_has_nul_byte (Z_STR_P (element ))) {
655+ zend_argument_value_error (2 , "individual argument must not contain null bytes" );
656+ efree (argv );
657+ RETURN_THROWS ();
658+ }
658659
659660 * current_arg = Z_STRVAL_P (element );
660- argi ++ ;
661661 current_arg ++ ;
662662 } ZEND_HASH_FOREACH_END ();
663663 * current_arg = NULL ;
@@ -667,39 +667,51 @@ PHP_FUNCTION(pcntl_exec)
667667 argv [1 ] = NULL ;
668668 }
669669
670- if ( ZEND_NUM_ARGS () == 3 ) {
670+ if (env_vars_ht != NULL ) {
671671 /* Build environment pair list */
672- SEPARATE_ARRAY ( envs ) ;
673- envs_hash = Z_ARRVAL_P ( envs ) ;
674- envc = zend_hash_num_elements ( envs_hash ) ;
672+ char * * pair ;
673+ zend_ulong key_num ;
674+ zend_string * key ;
675675
676- size_t envp_len = (envc + 1 );
676+ /* We want a NULL terminated array of char* */
677+ size_t envp_len = zend_hash_num_elements (env_vars_ht ) + 1 ;
677678 pair = envp = safe_emalloc (envp_len , sizeof (char * ), 0 );
678679 memset (envp , 0 , sizeof (char * ) * envp_len );
679- ZEND_HASH_FOREACH_KEY_VAL (envs_hash , key_num , key , element ) {
680- if (envi >= envc ) break ;
681- if (!key ) {
682- key = zend_long_to_str (key_num );
683- } else {
684- zend_string_addref (key );
680+ ZEND_HASH_FOREACH_KEY_VAL (env_vars_ht , key_num , key , element ) {
681+ zend_string * element_str = zval_try_get_string (element );
682+ if (element_str == NULL ) {
683+ goto cleanup_env_vars ;
685684 }
686685
687- if (!try_convert_to_string (element )) {
688- zend_string_release (key );
686+ if (zend_str_has_nul_byte (element_str )) {
687+ zend_argument_value_error (3 , "value for environment variable must not contain null bytes" );
688+ zend_string_release_ex (element_str , false);
689689 goto cleanup_env_vars ;
690690 }
691691
692+ /* putenv() allows integer environment variables */
693+ if (!key ) {
694+ key = zend_long_to_str ((zend_long ) key_num );
695+ } else {
696+ if (zend_str_has_nul_byte (key )) {
697+ zend_argument_value_error (3 , "name for environment variable must not contain null bytes" );
698+ zend_string_release_ex (element_str , false);
699+ goto cleanup_env_vars ;
700+ }
701+ zend_string_addref (key );
702+ }
703+
692704 /* Length of element + equal sign + length of key + null */
693- ZEND_ASSERT ( Z_STRLEN_P ( element ) < SIZE_MAX && ZSTR_LEN (key ) < SIZE_MAX );
694- * pair = safe_emalloc ( Z_STRLEN_P ( element ) + 1 , sizeof ( char ), ZSTR_LEN ( key ) + 1 );
695- pair_length = Z_STRLEN_P ( element ) + ZSTR_LEN (key ) + 2 ;
696- strlcpy (* pair , ZSTR_VAL ( key ), ZSTR_LEN (key ) + 1 ) ;
697- strlcat ( * pair , "=" , pair_length );
698- strlcat (* pair , Z_STRVAL_P ( element ), pair_length );
705+ * pair = safe_emalloc ( ZSTR_LEN ( element_str ) + 1 , sizeof ( char ), ZSTR_LEN (key ) + 1 );
706+ /* Copy key= element + final null byte into buffer */
707+ memcpy ( * pair , ZSTR_VAL ( key ), ZSTR_LEN (key )) ;
708+ (* pair )[ ZSTR_LEN (key )] = '=' ;
709+ /* Copy null byte */
710+ memcpy (* pair + ZSTR_LEN ( key ) + 1 , ZSTR_VAL ( element_str ), ZSTR_LEN ( element_str ) + 1 );
699711
700712 /* Cleanup */
701- zend_string_release_ex (key , 0 );
702- envi ++ ;
713+ zend_string_release_ex (key , false );
714+ zend_string_release_ex ( element_str , false) ;
703715 pair ++ ;
704716 } ZEND_HASH_FOREACH_END ();
705717 * (pair ) = NULL ;
0 commit comments