Skip to content

Commit 430b3ac

Browse files
committed
Refactor parts of SPL Dir/SplFileObject
This fixes a way it was possible to trigger an Internel Error by disabling function (via the INI setting) when SPL was acting as a proxy to the function call. Fix flock_compat layer as it needs to used in SPL now. Use macro to check if object is initialized Closes GH-6014
1 parent 7b3ac29 commit 430b3ac

File tree

7 files changed

+185
-161
lines changed

7 files changed

+185
-161
lines changed

ext/spl/config.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c, no,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
22
PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h])
33
PHP_ADD_EXTENSION_DEP(spl, pcre, true)
4+
PHP_ADD_EXTENSION_DEP(spl, standard, true)

ext/spl/spl_directory.c

Lines changed: 89 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020

2121
#include "php.h"
2222
#include "php_ini.h"
23-
#include "ext/standard/info.h"
2423
#include "ext/standard/file.h"
24+
#include "ext/standard/php_filestat.h"
25+
#include "ext/standard/flock_compat.h"
26+
#include "ext/standard/scanf.h"
2527
#include "ext/standard/php_string.h"
26-
#include "zend_compile.h"
2728
#include "zend_exceptions.h"
2829
#include "zend_interfaces.h"
2930

@@ -35,12 +36,6 @@
3536
#include "spl_directory_arginfo.h"
3637
#include "spl_exceptions.h"
3738

38-
#include "php.h"
39-
#include "fopen_wrappers.h"
40-
41-
#include "ext/standard/basic_functions.h"
42-
#include "ext/standard/php_filestat.h"
43-
4439
#define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0)
4540

4641
/* declare the class handlers */
@@ -57,6 +52,13 @@ PHPAPI zend_class_entry *spl_ce_GlobIterator;
5752
PHPAPI zend_class_entry *spl_ce_SplFileObject;
5853
PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
5954

55+
// TODO Use standard Error
56+
#define CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(spl_filesystem_object_pointer) \
57+
if (!(spl_filesystem_object_pointer)->u.file.stream) { \
58+
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized"); \
59+
RETURN_THROWS(); \
60+
}
61+
6062
static void spl_filesystem_file_free_line(spl_filesystem_object *intern) /* {{{ */
6163
{
6264
if (intern->u.file.current_line) {
@@ -1901,64 +1903,6 @@ static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent) /
19011903
return SUCCESS;
19021904
} /* }}} */
19031905

1904-
static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function *func_ptr, int pass_num_args, zval *return_value, zval *arg2) /* {{{ */
1905-
{
1906-
zend_fcall_info fci;
1907-
zend_fcall_info_cache fcic;
1908-
zval *zresource_ptr = &intern->u.file.zresource, *params;
1909-
int result;
1910-
int num_args = pass_num_args + (arg2 ? 2 : 1);
1911-
1912-
if (Z_ISUNDEF_P(zresource_ptr)) {
1913-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
1914-
return FAILURE;
1915-
}
1916-
1917-
params = (zval*)safe_emalloc(num_args, sizeof(zval), 0);
1918-
params[0] = *zresource_ptr;
1919-
1920-
if (arg2) {
1921-
params[1] = *arg2;
1922-
}
1923-
1924-
if (zend_get_parameters_array_ex(pass_num_args, params + (arg2 ? 2 : 1)) != SUCCESS) {
1925-
efree(params);
1926-
WRONG_PARAM_COUNT_WITH_RETVAL(FAILURE);
1927-
}
1928-
1929-
fci.size = sizeof(fci);
1930-
fci.object = NULL;
1931-
fci.retval = return_value;
1932-
fci.param_count = num_args;
1933-
fci.params = params;
1934-
fci.named_params = NULL;
1935-
ZVAL_STR(&fci.function_name, func_ptr->common.function_name);
1936-
1937-
fcic.function_handler = func_ptr;
1938-
fcic.called_scope = NULL;
1939-
fcic.object = NULL;
1940-
1941-
result = zend_call_function(&fci, &fcic);
1942-
1943-
if (result == FAILURE || Z_ISUNDEF_P(return_value)) {
1944-
RETVAL_FALSE;
1945-
}
1946-
1947-
efree(params);
1948-
return result;
1949-
} /* }}} */
1950-
1951-
#define FileFunctionCall(func_name, pass_num_args, arg2) /* {{{ */ \
1952-
{ \
1953-
zend_function *func_ptr; \
1954-
func_ptr = (zend_function *)zend_hash_str_find_ptr(EG(function_table), #func_name, sizeof(#func_name) - 1); \
1955-
if (func_ptr == NULL) { \
1956-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Internal error, function %s() not found. Please report", #func_name); \
1957-
return; \
1958-
} \
1959-
spl_filesystem_file_call(intern, func_ptr, pass_num_args, return_value, arg2); \
1960-
} /* }}} */
1961-
19621906
static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, int escape, zval *return_value) /* {{{ */
19631907
{
19641908
int ret = SUCCESS;
@@ -2075,7 +2019,7 @@ static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object
20752019

20762020
static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern) /* {{{ */
20772021
{
2078-
if(!intern->u.file.stream) {
2022+
if (!intern->u.file.stream) {
20792023
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
20802024
return;
20812025
}
@@ -2203,10 +2147,7 @@ PHP_METHOD(SplFileObject, eof)
22032147
RETURN_THROWS();
22042148
}
22052149

2206-
if(!intern->u.file.stream) {
2207-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2208-
RETURN_THROWS();
2209-
}
2150+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
22102151

22112152
RETURN_BOOL(php_stream_eof(intern->u.file.stream));
22122153
} /* }}} */
@@ -2239,10 +2180,7 @@ PHP_METHOD(SplFileObject, fgets)
22392180
RETURN_THROWS();
22402181
}
22412182

2242-
if(!intern->u.file.stream) {
2243-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2244-
RETURN_THROWS();
2245-
}
2183+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
22462184

22472185
if (spl_filesystem_file_read(intern, 0) == FAILURE) {
22482186
RETURN_FALSE;
@@ -2259,10 +2197,7 @@ PHP_METHOD(SplFileObject, current)
22592197
RETURN_THROWS();
22602198
}
22612199

2262-
if(!intern->u.file.stream) {
2263-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2264-
RETURN_THROWS();
2265-
}
2200+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
22662201

22672202
if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) {
22682203
spl_filesystem_file_read_line(ZEND_THIS, intern, 1);
@@ -2382,15 +2317,6 @@ PHP_METHOD(SplFileObject, getChildren)
23822317
/* return NULL */
23832318
} /* }}} */
23842319

2385-
/* {{{ FileFunction */
2386-
#define FileFunction(func_name) \
2387-
PHP_METHOD(SplFileObject, func_name) \
2388-
{ \
2389-
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS); \
2390-
FileFunctionCall(func_name, ZEND_NUM_ARGS(), NULL); \
2391-
}
2392-
/* }}} */
2393-
23942320
/* {{{ Return current line as csv */
23952321
PHP_METHOD(SplFileObject, fgetcsv)
23962322
{
@@ -2402,10 +2328,7 @@ PHP_METHOD(SplFileObject, fgetcsv)
24022328

24032329
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
24042330

2405-
if(!intern->u.file.stream) {
2406-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2407-
RETURN_THROWS();
2408-
}
2331+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
24092332

24102333
switch(ZEND_NUM_ARGS())
24112334
{
@@ -2570,19 +2493,51 @@ PHP_METHOD(SplFileObject, getCsvControl)
25702493
}
25712494
/* }}} */
25722495

2573-
/* {{{ Portable file locking */
2574-
FileFunction(flock)
2496+
static int flock_values[] = { LOCK_SH, LOCK_EX, LOCK_UN };
2497+
2498+
/* {{{ Portable file locking, copy pasted from ext/standard/file.c flock() function.
2499+
* This is done to prevent this to fail if flock is disabled via disable_functions */
2500+
PHP_METHOD(SplFileObject, flock)
2501+
{
2502+
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
2503+
zval *wouldblock = NULL;
2504+
int act;
2505+
zend_long operation = 0;
2506+
2507+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z", &operation, &wouldblock) == FAILURE) {
2508+
RETURN_THROWS();
2509+
}
2510+
2511+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2512+
2513+
act = operation & PHP_LOCK_UN;
2514+
if (act < 1 || act > 3) {
2515+
zend_argument_value_error(1, "must be either LOCK_SH, LOCK_EX, or LOCK_UN");
2516+
RETURN_THROWS();
2517+
}
2518+
2519+
if (wouldblock) {
2520+
ZEND_TRY_ASSIGN_REF_LONG(wouldblock, 0);
2521+
}
2522+
2523+
/* flock_values contains all possible actions if (operation & PHP_LOCK_NB) we won't block on the lock */
2524+
act = flock_values[act - 1] | (operation & PHP_LOCK_NB ? LOCK_NB : 0);
2525+
if (php_stream_lock(intern->u.file.stream, act)) {
2526+
if (operation && errno == EWOULDBLOCK && wouldblock) {
2527+
ZEND_TRY_ASSIGN_REF_LONG(wouldblock, 1);
2528+
}
2529+
RETURN_FALSE;
2530+
}
2531+
RETURN_TRUE;
2532+
}
25752533
/* }}} */
25762534

25772535
/* {{{ Flush the file */
25782536
PHP_METHOD(SplFileObject, fflush)
25792537
{
25802538
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
25812539

2582-
if(!intern->u.file.stream) {
2583-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2584-
RETURN_THROWS();
2585-
}
2540+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
25862541

25872542
RETURN_BOOL(!php_stream_flush(intern->u.file.stream));
25882543
} /* }}} */
@@ -2593,10 +2548,7 @@ PHP_METHOD(SplFileObject, ftell)
25932548
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
25942549
zend_long ret;
25952550

2596-
if(!intern->u.file.stream) {
2597-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2598-
RETURN_THROWS();
2599-
}
2551+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
26002552

26012553
ret = php_stream_tell(intern->u.file.stream);
26022554

@@ -2617,10 +2569,7 @@ PHP_METHOD(SplFileObject, fseek)
26172569
RETURN_THROWS();
26182570
}
26192571

2620-
if(!intern->u.file.stream) {
2621-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2622-
RETURN_THROWS();
2623-
}
2572+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
26242573

26252574
spl_filesystem_file_free_line(intern);
26262575
RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, (int)whence));
@@ -2633,10 +2582,7 @@ PHP_METHOD(SplFileObject, fgetc)
26332582
char buf[2];
26342583
int result;
26352584

2636-
if(!intern->u.file.stream) {
2637-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2638-
RETURN_THROWS();
2639-
}
2585+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
26402586

26412587
spl_filesystem_file_free_line(intern);
26422588

@@ -2660,28 +2606,35 @@ PHP_METHOD(SplFileObject, fpassthru)
26602606
{
26612607
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
26622608

2663-
if(!intern->u.file.stream) {
2664-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2665-
RETURN_THROWS();
2666-
}
2609+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
26672610

26682611
RETURN_LONG(php_stream_passthru(intern->u.file.stream));
26692612
} /* }}} */
26702613

26712614
/* {{{ Implements a mostly ANSI compatible fscanf() */
26722615
PHP_METHOD(SplFileObject, fscanf)
26732616
{
2617+
int result, num_varargs = 0;
2618+
zend_string *format_str;
2619+
zval *varargs= NULL;
26742620
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
26752621

2676-
if(!intern->u.file.stream) {
2677-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2622+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S*", &format_str, &varargs, &num_varargs) == FAILURE) {
26782623
RETURN_THROWS();
26792624
}
26802625

2681-
spl_filesystem_file_free_line(intern);
2682-
intern->u.file.current_line_num++;
2626+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
26832627

2684-
FileFunctionCall(fscanf, ZEND_NUM_ARGS(), NULL);
2628+
/* Get next line */
2629+
if (spl_filesystem_file_read(intern, 0) == FAILURE) {
2630+
RETURN_THROWS();
2631+
}
2632+
2633+
result = php_sscanf_internal(intern->u.file.current_line, ZSTR_VAL(format_str), num_varargs, varargs, 0, return_value);
2634+
2635+
if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
2636+
WRONG_PARAM_COUNT;
2637+
}
26852638
}
26862639
/* }}} */
26872640

@@ -2698,10 +2651,7 @@ PHP_METHOD(SplFileObject, fwrite)
26982651
RETURN_THROWS();
26992652
}
27002653

2701-
if(!intern->u.file.stream) {
2702-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2703-
RETURN_THROWS();
2704-
}
2654+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
27052655

27062656
if (ZEND_NUM_ARGS() > 1) {
27072657
if (length >= 0) {
@@ -2732,10 +2682,7 @@ PHP_METHOD(SplFileObject, fread)
27322682
RETURN_THROWS();
27332683
}
27342684

2735-
if(!intern->u.file.stream) {
2736-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2737-
RETURN_THROWS();
2738-
}
2685+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
27392686

27402687
if (length <= 0) {
27412688
php_error_docref(NULL, E_WARNING, "Length parameter must be greater than 0");
@@ -2750,7 +2697,18 @@ PHP_METHOD(SplFileObject, fread)
27502697
}
27512698

27522699
/* {{{ Stat() on a filehandle */
2753-
FileFunction(fstat)
2700+
PHP_METHOD(SplFileObject, fstat)
2701+
{
2702+
spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
2703+
2704+
if (zend_parse_parameters_none() == FAILURE) {
2705+
RETURN_THROWS();
2706+
}
2707+
2708+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2709+
2710+
php_fstat(intern->u.file.stream, return_value);
2711+
}
27542712
/* }}} */
27552713

27562714
/* {{{ Truncate file to 'size' length */
@@ -2763,10 +2721,7 @@ PHP_METHOD(SplFileObject, ftruncate)
27632721
RETURN_THROWS();
27642722
}
27652723

2766-
if(!intern->u.file.stream) {
2767-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2768-
RETURN_THROWS();
2769-
}
2724+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
27702725

27712726
if (!php_stream_truncate_supported(intern->u.file.stream)) {
27722727
zend_throw_exception_ex(spl_ce_LogicException, 0, "Can't truncate file %s", intern->file_name);
@@ -2785,10 +2740,8 @@ PHP_METHOD(SplFileObject, seek)
27852740
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &line_pos) == FAILURE) {
27862741
RETURN_THROWS();
27872742
}
2788-
if(!intern->u.file.stream) {
2789-
zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2790-
RETURN_THROWS();
2791-
}
2743+
2744+
CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
27922745

27932746
if (line_pos < 0) {
27942747
zend_throw_exception_ex(spl_ce_LogicException, 0, "Can't seek file %s to negative line " ZEND_LONG_FMT, intern->file_name, line_pos);

0 commit comments

Comments
 (0)