@@ -620,44 +620,44 @@ PHP_FUNCTION(pcntl_wstopsig)
620
620
/* {{{ Executes specified program in current process space as defined by exec(2) */
621
621
PHP_FUNCTION (pcntl_exec )
622
622
{
623
- zval * args = NULL , * envs = NULL ;
623
+ zval * args = NULL ;
624
+ HashTable * env_vars_ht = NULL ;
624
625
zval * element ;
625
- HashTable * args_hash , * envs_hash ;
626
- int argc = 0 , argi = 0 ;
627
- int envc = 0 , envi = 0 ;
628
626
char * * argv = NULL , * * envp = NULL ;
629
- char * * current_arg , * * pair ;
630
- size_t pair_length ;
631
- zend_string * key ;
632
627
char * path ;
633
628
size_t path_len ;
634
- zend_ulong key_num ;
635
629
636
630
ZEND_PARSE_PARAMETERS_START (1 , 3 )
637
631
Z_PARAM_PATH (path , path_len )
638
632
Z_PARAM_OPTIONAL
639
633
Z_PARAM_ARRAY (args )
640
- Z_PARAM_ARRAY ( envs )
634
+ Z_PARAM_ARRAY_HT ( env_vars_ht )
641
635
ZEND_PARSE_PARAMETERS_END ();
642
636
643
- if (ZEND_NUM_ARGS () > 1 ) {
637
+ if (args != NULL) {
638
+ // TODO Check array is a list?
644
639
/* Build argument list */
645
640
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 );
648
643
644
+ /* We want a NULL terminated array of char* with the first entry being the path,
645
+ * followed by the arguments */
649
646
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 ) {
654
650
if (!try_convert_to_string (element )) {
655
651
efree (argv );
656
652
RETURN_THROWS ();
657
653
}
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
+ }
658
659
659
660
* current_arg = Z_STRVAL_P (element );
660
- argi ++ ;
661
661
current_arg ++ ;
662
662
} ZEND_HASH_FOREACH_END ();
663
663
* current_arg = NULL ;
@@ -667,39 +667,51 @@ PHP_FUNCTION(pcntl_exec)
667
667
argv [1 ] = NULL ;
668
668
}
669
669
670
- if ( ZEND_NUM_ARGS () == 3 ) {
670
+ if (env_vars_ht != NULL ) {
671
671
/* 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 ;
675
675
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 ;
677
678
pair = envp = safe_emalloc (envp_len , sizeof (char * ), 0 );
678
679
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 ;
685
684
}
686
685
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);
689
689
goto cleanup_env_vars ;
690
690
}
691
691
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
+
692
704
/* 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 );
699
711
700
712
/* 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) ;
703
715
pair ++ ;
704
716
} ZEND_HASH_FOREACH_END ();
705
717
* (pair ) = NULL ;
0 commit comments