@@ -620,86 +620,88 @@ 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
+ // TODO Check element does not have nul bytes?
658
655
659
656
* current_arg = Z_STRVAL_P (element );
660
- argi ++ ;
661
657
current_arg ++ ;
662
658
} ZEND_HASH_FOREACH_END ();
663
659
* current_arg = NULL ;
664
660
} else {
665
- argv = emalloc ( 2 * sizeof (char * ));
661
+ argv = safe_emalloc ( 2 , sizeof (char * ), 0 );
666
662
argv [0 ] = path ;
667
663
argv [1 ] = NULL ;
668
664
}
669
665
670
- if ( ZEND_NUM_ARGS () == 3 ) {
666
+ if (env_vars_ht != NULL ) {
671
667
/* Build environment pair list */
672
- SEPARATE_ARRAY ( envs ) ;
673
- envs_hash = Z_ARRVAL_P ( envs ) ;
674
- envc = zend_hash_num_elements ( envs_hash ) ;
668
+ char * * pair ;
669
+ zend_ulong key_num ;
670
+ zend_string * key ;
675
671
676
- size_t envp_len = (envc + 1 );
672
+ /* We want a NULL terminated array of char* */
673
+ size_t envp_len = zend_hash_num_elements (env_vars_ht ) + 1 ;
677
674
pair = envp = safe_emalloc (envp_len , sizeof (char * ), 0 );
678
675
memset (envp , 0 , sizeof (char * ) * envp_len );
679
- ZEND_HASH_FOREACH_KEY_VAL (envs_hash , key_num , key , element ) {
680
- if (envi >= envc ) break ;
676
+ ZEND_HASH_FOREACH_KEY_VAL (env_vars_ht , key_num , key , element ) {
677
+ zend_string * element_str = zval_try_get_string (element );
678
+ if (element_str == NULL ) {
679
+ goto cleanup_env_vars ;
680
+ }
681
+
681
682
if (!key ) {
682
- key = zend_long_to_str (key_num );
683
+ // TODO Does it even make sense to have an environment variable which is an integer?
684
+ key = zend_long_to_str ((zend_long ) key_num );
683
685
} else {
684
686
zend_string_addref (key );
685
687
}
686
688
687
- if (!try_convert_to_string (element )) {
688
- zend_string_release (key );
689
- goto cleanup_env_vars ;
690
- }
689
+ // TODO Check key and element do not have nul bytes?
691
690
692
691
/* 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 );
692
+ const uint8_t equal_len = strlen ("=" );
693
+ size_t pair_length = ZSTR_LEN (element_str ) + equal_len + ZSTR_LEN (key ) + 1 ;
694
+ ZEND_ASSERT (pair_length < SIZE_MAX );
695
+ * pair = emalloc (pair_length );
696
+ /* Copy key=element + final null byte into buffer */
697
+ memcpy (* pair , ZSTR_VAL (key ), ZSTR_LEN (key ));
698
+ memcpy (* pair + ZSTR_LEN (key ), "=" , equal_len );
699
+ /* Copy null byte */
700
+ memcpy (* pair + ZSTR_LEN (key ) + equal_len , ZSTR_VAL (element_str ), ZSTR_LEN (element_str ) + 1 );
699
701
700
702
/* Cleanup */
701
- zend_string_release_ex (key , 0 );
702
- envi ++ ;
703
+ zend_string_release_ex (key , false );
704
+ zend_string_release_ex ( element_str , false) ;
703
705
pair ++ ;
704
706
} ZEND_HASH_FOREACH_END ();
705
707
* (pair ) = NULL ;
0 commit comments