Skip to content

Commit d7da2cb

Browse files
Check all keys before traversing the segments
1 parent 63de950 commit d7da2cb

5 files changed

Lines changed: 47 additions & 20 deletions

File tree

ext/standard/array.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6922,22 +6922,31 @@ static zval* array_get_nested(HashTable *ht, HashTable *path)
69226922
uint32_t num_segments = zend_hash_num_elements(path);
69236923
uint32_t segment_index = 0;
69246924

6925-
/* Iterate through each segment in the path array */
6925+
/* First pass: validate all path segments are valid types */
6926+
ZEND_HASH_FOREACH_VAL(path, segment_val) {
6927+
/* Dereference segment if it's a reference */
6928+
ZVAL_DEREF(segment_val);
6929+
6930+
/* Segment must be a string or int */
6931+
if (Z_TYPE_P(segment_val) != IS_STRING && Z_TYPE_P(segment_val) != IS_LONG) {
6932+
/* Invalid segment type - throw TypeError */
6933+
zend_type_error("Path segment must be of type string|int, %s given", zend_zval_value_name(segment_val));
6934+
return NULL;
6935+
}
6936+
} ZEND_HASH_FOREACH_END();
6937+
6938+
/* Second pass: traverse the array using the validated path */
69266939
ZEND_HASH_FOREACH_VAL(path, segment_val) {
69276940
segment_index++;
69286941

69296942
/* Dereference segment if it's a reference */
69306943
ZVAL_DEREF(segment_val);
69316944

6932-
/* Segment must be a string or int */
6945+
/* Look up the segment (already validated to be string or int) */
69336946
if (Z_TYPE_P(segment_val) == IS_STRING) {
69346947
current = zend_symtable_find(current_ht, Z_STR_P(segment_val));
6935-
} else if (Z_TYPE_P(segment_val) == IS_LONG) {
6936-
current = zend_hash_index_find(current_ht, Z_LVAL_P(segment_val));
69376948
} else {
6938-
/* Invalid segment type - throw TypeError */
6939-
zend_type_error("Path segment must be of type string|int, %s given", zend_zval_value_name(segment_val));
6940-
return NULL;
6949+
current = zend_hash_index_find(current_ht, Z_LVAL_P(segment_val));
69416950
}
69426951

69436952
/* If segment not found, return NULL */

ext/standard/basic_functions_arginfo.h

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/basic_functions_decl.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/tests/array/array_path_exists.phpt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ try {
3838
echo $e->getMessage() . "\n";
3939
}
4040

41+
// Test with invalid segment type even when path doesn't exist
42+
$empty_array = [];
43+
try {
44+
var_dump(array_path_exists($empty_array, ['foo', 'bar', new stdClass()]));
45+
} catch (TypeError $e) {
46+
echo $e->getMessage() . "\n";
47+
}
48+
4149
// Test with reference to an array in the path
4250
$array2 = ['world'];
4351
$array_with_ref = ['hello' => &$array2];
@@ -63,6 +71,7 @@ bool(true)
6371
bool(false)
6472
bool(true)
6573
Path segment must be of type string|int, stdClass given
74+
Path segment must be of type string|int, stdClass given
6675
bool(true)
6776
bool(true)
6877
Done

ext/standard/tests/array/array_path_get.phpt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ try {
3636
echo $e->getMessage() . "\n";
3737
}
3838

39+
// Test with invalid segment type even when path doesn't exist
40+
$empty_array = [];
41+
try {
42+
var_dump(array_path_get($empty_array, ['foo', 'bar', new stdClass()], 'default'));
43+
} catch (TypeError $e) {
44+
echo $e->getMessage() . "\n";
45+
}
46+
3947
// Test with references - ensure returned value is a copy, not a reference
4048
$ref_array = ['data' => ['value' => 'original']];
4149
$ref =& $ref_array['data']['value'];
@@ -76,6 +84,7 @@ string(5) "Alice"
7684
string(3) "Bob"
7785
int(75)
7886
Path segment must be of type string|int, stdClass given
87+
Path segment must be of type string|int, stdClass given
7988
string(8) "original"
8089
string(8) "original"
8190
string(7) "default"

0 commit comments

Comments
 (0)