Skip to content

Commit 19fcda2

Browse files
committed
Convert command in proc_open() to zend_string
This prevents a call to strlen() on Windows
1 parent a837d35 commit 19fcda2

File tree

1 file changed

+43
-43
lines changed

1 file changed

+43
-43
lines changed

ext/standard/proc_open.c

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#include "php_globals.h"
2727
#include "SAPI.h"
2828
#include "main/php_network.h"
29-
#include "zend_smart_string.h"
29+
#include "zend_smart_str.h"
3030

3131
#if HAVE_SYS_WAIT_H
3232
#include <sys/wait.h>
@@ -485,62 +485,63 @@ static zend_string *get_valid_arg_string(zval *zv, int elem_num) {
485485
}
486486

487487
#ifdef PHP_WIN32
488-
static void append_backslashes(smart_string *str, size_t num_bs)
488+
static void append_backslashes(smart_str *str, size_t num_bs)
489489
{
490490
for (size_t i = 0; i < num_bs; i++) {
491-
smart_string_appendc(str, '\\');
491+
smart_str_appendc(str, '\\');
492492
}
493493
}
494494

495495
/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments */
496-
static void append_win_escaped_arg(smart_string *str, char *arg)
496+
static void append_win_escaped_arg(smart_str *str, zend_string *arg)
497497
{
498-
char c;
499498
size_t num_bs = 0;
500-
smart_string_appendc(str, '"');
501-
while ((c = *arg)) {
499+
500+
smart_str_appendc(str, '"');
501+
for (size_t i = 0; i < ZSTR_LEN(arg); ++i) {
502+
char c = ZSTR_VAL(arg)[i];
502503
if (c == '\\') {
503504
num_bs++;
504-
} else {
505-
if (c == '"') {
506-
/* Backslashes before " need to be doubled. */
507-
num_bs = num_bs * 2 + 1;
508-
}
509-
append_backslashes(str, num_bs);
510-
smart_string_appendc(str, c);
511-
num_bs = 0;
505+
continue;
506+
}
507+
508+
if (c == '"') {
509+
/* Backslashes before " need to be doubled. */
510+
num_bs = num_bs * 2 + 1;
512511
}
513-
arg++;
512+
append_backslashes(str, num_bs);
513+
smart_str_appendc(str, c);
514+
num_bs = 0;
514515
}
515516
append_backslashes(str, num_bs * 2);
516-
smart_string_appendc(str, '"');
517+
smart_str_appendc(str, '"');
517518
}
518519

519-
static char *create_win_command_from_args(HashTable *args)
520+
static zend_string *create_win_command_from_args(HashTable *args)
520521
{
521-
smart_string str = {0};
522+
smart_str str = {0};
522523
zval *arg_zv;
523524
bool is_prog_name = 1;
524525
int elem_num = 0;
525526

526527
ZEND_HASH_FOREACH_VAL(args, arg_zv) {
527528
zend_string *arg_str = get_valid_arg_string(arg_zv, ++elem_num);
528529
if (!arg_str) {
529-
smart_string_free(&str);
530+
smart_str_free(&str);
530531
return NULL;
531532
}
532533

533534
if (!is_prog_name) {
534-
smart_string_appendc(&str, ' ');
535+
smart_str_appendc(&str, ' ');
535536
}
536537

537-
append_win_escaped_arg(&str, ZSTR_VAL(arg_str));
538+
append_win_escaped_arg(&str, arg_str);
538539

539540
is_prog_name = 0;
540541
zend_string_release(arg_str);
541542
} ZEND_HASH_FOREACH_END();
542-
smart_string_0(&str);
543-
return str.c;
543+
smart_str_0(&str);
544+
return str.s;
544545
}
545546

546547
/* Get a boolean option from the `other_options` array which can be passed to `proc_open`.
@@ -611,10 +612,10 @@ static int convert_command_to_use_shell(wchar_t **cmdw, size_t cmdw_len)
611612
#endif
612613

613614
/* Convert command parameter array passed as first argument to `proc_open` into command string */
614-
static char* get_command_from_array(HashTable *array, char ***argv, int num_elems)
615+
static zend_string* get_command_from_array(HashTable *array, char ***argv, int num_elems)
615616
{
616617
zval *arg_zv;
617-
char *command = NULL;
618+
zend_string *command = NULL;
618619
int i = 0;
619620

620621
*argv = safe_emalloc(sizeof(char *), num_elems + 1, 0);
@@ -625,13 +626,13 @@ static char* get_command_from_array(HashTable *array, char ***argv, int num_elem
625626
/* Terminate with NULL so exit_fail code knows how many entries to free */
626627
(*argv)[i] = NULL;
627628
if (command != NULL) {
628-
efree(command);
629+
zend_string_release_ex(command, false);
629630
}
630631
return NULL;
631632
}
632633

633634
if (i == 0) {
634-
command = estrdup(ZSTR_VAL(arg_str));
635+
command = zend_string_copy(arg_str);
635636
}
636637

637638
(*argv)[i++] = estrdup(ZSTR_VAL(arg_str));
@@ -1005,7 +1006,6 @@ PHP_FUNCTION(proc_open)
10051006
size_t cwd_len = 0; /* Optional argument */
10061007
zval *environment = NULL, *other_options = NULL; /* Optional arguments */
10071008

1008-
char *command = NULL;
10091009
php_process_env env;
10101010
int ndesc = 0;
10111011
int i;
@@ -1057,18 +1057,16 @@ PHP_FUNCTION(proc_open)
10571057
#ifdef PHP_WIN32
10581058
/* Automatically bypass shell if command is given as an array */
10591059
bypass_shell = 1;
1060-
command = create_win_command_from_args(command_ht);
1061-
if (!command) {
1060+
command_str = create_win_command_from_args(command_ht);
1061+
if (!command_str) {
10621062
RETURN_FALSE;
10631063
}
10641064
#else
1065-
command = get_command_from_array(command_ht, &argv, num_elems);
1066-
if (command == NULL) {
1065+
command_str = get_command_from_array(command_ht, &argv, num_elems);
1066+
if (!command_str) {
10671067
goto exit_fail;
10681068
}
10691069
#endif
1070-
} else {
1071-
command = estrdup(ZSTR_VAL(command_str));
10721070
}
10731071

10741072
#ifdef PHP_WIN32
@@ -1155,7 +1153,7 @@ PHP_FUNCTION(proc_open)
11551153
}
11561154
}
11571155

1158-
cmdw = php_win32_cp_conv_any_to_w(command, strlen(command), &cmdw_len);
1156+
cmdw = php_win32_cp_conv_any_to_w(ZSTR_VAL(command_str), ZSTR_LEN(command_str), &cmdw_len);
11591157
if (!cmdw) {
11601158
php_error_docref(NULL, E_WARNING, "Command conversion failed");
11611159
goto exit_fail;
@@ -1206,12 +1204,12 @@ PHP_FUNCTION(proc_open)
12061204
if (env.envarray) {
12071205
environ = env.envarray;
12081206
}
1209-
execvp(command, argv);
1207+
execvp(ZSTR_VAL(command_str), argv);
12101208
} else {
12111209
if (env.envarray) {
1212-
execle("/bin/sh", "sh", "-c", command, NULL, env.envarray);
1210+
execle("/bin/sh", "sh", "-c", ZSTR_VAL(command_str), NULL, env.envarray);
12131211
} else {
1214-
execl("/bin/sh", "sh", "-c", command, NULL);
1212+
execl("/bin/sh", "sh", "-c", ZSTR_VAL(command_str), NULL);
12151213
}
12161214
}
12171215

@@ -1237,7 +1235,7 @@ PHP_FUNCTION(proc_open)
12371235
}
12381236

12391237
proc = (php_process_handle*) emalloc(sizeof(php_process_handle));
1240-
proc->command = command;
1238+
proc->command = estrdup(ZSTR_VAL(command_str));
12411239
proc->pipes = emalloc(sizeof(zend_resource *) * ndesc);
12421240
proc->npipes = ndesc;
12431241
proc->child = child;
@@ -1308,12 +1306,14 @@ PHP_FUNCTION(proc_open)
13081306
} else {
13091307
exit_fail:
13101308
_php_free_envp(env);
1311-
if (command) {
1312-
efree(command);
1313-
}
13141309
RETVAL_FALSE;
13151310
}
13161311

1312+
/* the command_str needs to be freed if it was created by parsing an array */
1313+
if (command_ht && command_str) {
1314+
zend_string_release_ex(command_str, false);
1315+
}
1316+
13171317
#ifdef PHP_WIN32
13181318
free(cwdw);
13191319
free(cmdw);

0 commit comments

Comments
 (0)