diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c243659..d9573e2 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ github: krakjoe +custom: https://gofund.me/c34f3dde diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index deca4e3..374c609 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,10 @@ name: Build and Test -on: - push: - pull_request: - schedule: - - cron: '18 3 * * *' +on: [push, pull_request, workflow_dispatch] jobs: ubuntu: strategy: matrix: - version: ["PHP-8.0", "master"] + version: ["PHP-8.0", "PHP-8.1", "PHP-8.2", "PHP-8.3", "master"] opcache: ["opcache.enable_cli=0", "opcache.enable_cli=1"] debug: ["enable-debug", "disable-debug"] runs-on: ubuntu-latest @@ -33,7 +29,7 @@ jobs: make -j$(nproc) sudo make install - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Generate Build Files run: /opt/bin/phpize - name: Configure Build @@ -53,7 +49,7 @@ jobs: - name: Generate Test Coverage run: lcov -c --directory ./src/.libs --exclude *Zend* --exclude */usr/include* --output-file coverage.info - name: Coveralls - uses: coverallsapp/github-action@master + uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: coverage.info @@ -63,16 +59,16 @@ jobs: shell: cmd strategy: matrix: - version: ["8.0", "8.1"] + version: ["8.0", "8.1", "8.2", "8.3", "8.4"] arch: [x64, x86] ts: [nts, ts] - runs-on: windows-latest + runs-on: windows-2022 steps: - name: Checkout uopz - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP id: setup-php - uses: cmb69/setup-php-sdk@v0.7 + uses: php/setup-php-sdk@v0.9 with: version: ${{matrix.version}} arch: ${{matrix.arch}} @@ -89,4 +85,4 @@ jobs: - name: Build run: nmake - name: Run Tests - run: nmake test TESTS=tests + run: nmake test TESTS="--show-diff tests" diff --git a/config.m4 b/config.m4 index f07377e..2249e00 100644 --- a/config.m4 +++ b/config.m4 @@ -1,30 +1,45 @@ -PHP_ARG_ENABLE(uopz, whether to enable uopz support, -[ --enable-uopz Enable uopz support]) +PHP_ARG_ENABLE([uopz], + [whether to enable uopz support], + [AS_HELP_STRING([--enable-uopz], + [Enable uopz support])]) -PHP_ARG_ENABLE(uopz-coverage, whether to enable uopz coverage support, -[ --enable-uopz-coverage Enable uopz coverage support], no, no) +PHP_ARG_ENABLE([uopz-coverage], + [whether to enable uopz coverage support], + [AS_HELP_STRING([--enable-uopz-coverage], + [Enable uopz coverage support])], + [no], + [no]) -PHP_ARG_WITH(uopz-sanitize, whether to enable AddressSanitizer for uopz, -[ --with-uopz-sanitize Build uopz with AddressSanitizer support], no, no) +PHP_ARG_WITH([uopz-sanitize], + [whether to enable AddressSanitizer for uopz], + [AS_HELP_STRING([--with-uopz-sanitize], + [Build uopz with AddressSanitizer support])], + [no], + [no]) if test "$PHP_UOPZ" != "no"; then - if test "$PHP_UOPZ_SANITIZE" != "no"; then + AS_VAR_IF([PHP_UOPZ_SANITIZE], [no],, [ EXTRA_LDFLAGS="-lasan" - EXTRA_CFLAGS="-fsanitize=address -fno-omit-frame-pointer" - PHP_SUBST(EXTRA_LDFLAGS) - PHP_SUBST(EXTRA_CFLAGS) - fi + EXTRA_CFLAGS="-fsanitize=address -fno-omit-frame-pointer" + PHP_SUBST([EXTRA_LDFLAGS]) + PHP_SUBST([EXTRA_CFLAGS]) + ]) - PHP_NEW_EXTENSION(uopz, uopz.c src/util.c src/return.c src/hook.c src/constant.c src/function.c src/class.c src/handlers.c src/executors.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) - PHP_ADD_BUILD_DIR($ext_builddir/src, 1) - PHP_ADD_INCLUDE($ext_builddir) + PHP_NEW_EXTENSION([uopz], m4_normalize([ + src/class.c + src/constant.c + src/executors.c + src/function.c + src/handlers.c + src/hook.c + src/return.c + src/util.c + uopz.c + ]), + [$ext_shared],, + [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) + PHP_ADD_BUILD_DIR([$ext_builddir/src]) + PHP_ADD_INCLUDE([$ext_builddir]) - AC_MSG_CHECKING([uopz coverage]) - if test "$PHP_UOPZ_COVERAGE" != "no"; then - AC_MSG_RESULT([enabled]) - - PHP_ADD_MAKEFILE_FRAGMENT - else - AC_MSG_RESULT([disabled]) - fi + AS_VAR_IF([PHP_UOPZ_COVERAGE], [no],, [PHP_ADD_MAKEFILE_FRAGMENT]) fi diff --git a/config.w32 b/config.w32 index 802f717..f860508 100644 --- a/config.w32 +++ b/config.w32 @@ -4,12 +4,12 @@ ARG_ENABLE("uopz", "for uopz support", "no"); if (PHP_UOPZ != "no") { - EXTENSION("uopz", "uopz.c"); + EXTENSION("uopz", "uopz.c", null, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); ADD_SOURCES( - configure_module_dirname + "/src", - "util.c return.c hook.c constant.c function.c class.c handlers.c executors.c", + configure_module_dirname + "/src", + "util.c return.c hook.c constant.c function.c class.c handlers.c executors.c", "uopz" - ); + ); ADD_FLAG("CFLAGS_UOPZ", "/I" + configure_module_dirname + ""); } diff --git a/src/function.c b/src/function.c index 671ae8c..bde335d 100644 --- a/src/function.c +++ b/src/function.c @@ -323,6 +323,7 @@ zend_bool uopz_set_static(zend_class_entry *clazz, zend_string *function, zval * zval_ptr_dtor(v); } + ZEND_ASSERT(Z_TYPE_P(statics) == IS_ARRAY); if (!(y = zend_hash_find(Z_ARRVAL_P(statics), k))) { ZVAL_NULL(v); diff --git a/tests/002.phpt b/tests/002.phpt index fceaf26..29235fc 100644 --- a/tests/002.phpt +++ b/tests/002.phpt @@ -34,15 +34,15 @@ var_dump(uopz_set_return(Foo::class, "bazQuux", function(){})); var_dump(uopz_get_return(Foo::class, "bazQuux")); ?> ---EXPECT-- +--EXPECTF-- bool(true) bool(true) bool(true) -object(Closure)#1 (0) { +object(Closure)#1 (%d) {%A } NULL bool(true) bool(true) bool(true) -object(Closure)#2 (0) { +object(Closure)#2 (%d) {%A } diff --git a/tests/003.phpt b/tests/003.phpt index 212579b..59bc90d 100644 --- a/tests/003.phpt +++ b/tests/003.phpt @@ -39,15 +39,15 @@ var_dump(uopz_unset_return("bar")); var_dump(uopz_get_return(DateTime::class, "__construct")); ?> ---EXPECT-- +--EXPECTF-- bool(true) bool(true) bool(true) bool(false) bool(false) bool(true) -object(Closure)#2 (0) { -} +object(Closure)#2 (%d) { +%A} bool(true) bool(true) NULL diff --git a/tests/007.phpt b/tests/007.phpt index a195901..bf862f6 100644 --- a/tests/007.phpt +++ b/tests/007.phpt @@ -2,6 +2,11 @@ uopz_get_static --EXTENSIONS-- uopz +--SKIPIF-- += 0) die("skip only for PHP < 8.3.0"); +?> --INI-- uopz.disable=0 --FILE-- diff --git a/tests/007_1.phpt b/tests/007_1.phpt new file mode 100644 index 0000000..b4942cc --- /dev/null +++ b/tests/007_1.phpt @@ -0,0 +1,114 @@ +--TEST-- +uopz_get_static +--EXTENSIONS-- +uopz +--SKIPIF-- += 8.3.0"); +?> +--INI-- +uopz.disable=0 +--FILE-- +method(); + +var_dump(uopz_get_static(Foo::class, "method")); + +try { + uopz_get_static(Foo::class, "none"); +} catch (RuntimeException $ex) { + var_dump($ex->getMessage()); +} + +try { + uopz_get_static("none"); +} catch (RuntimeException $ex) { + var_dump($ex->getMessage()); +} + +try { + uopz_get_static(DateTime::class, "__construct"); +} catch(RuntimeException $ex) { + var_dump($ex->getMessage()); +} + +try { + uopz_get_static("phpversion"); +} catch(RuntimeException $ex) { + var_dump($ex->getMessage()); +} + +try { + uopz_get_static(Foo::class, "nostatics"); +} catch(RuntimeException $ex) { + var_dump($ex->getMessage()); +} + +try { + uopz_get_static("nostatics"); +} catch(RuntimeException $ex) { + var_dump($ex->getMessage()); +} +?> +--EXPECTF-- +array(2) { + ["vars"]=> + array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + } + ["bar"]=> + NULL +} +array(2) { + ["vars"]=> + array(6) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + [5]=> + int(6) + } + ["bar"]=> + string(3) "bar" +} +string(%d) "failed to get statics from method %s::%s, it does not exist" +string(%d) "failed to get statics from function %s, it does not exist" +string(%d) "failed to get statics from internal method %s::%s" +string(%d) "failed to get statics from internal function %s" +string(%d) "failed to set statics in method %s::%s, no statics declared" +string(%d) "failed to set statics in function %s, no statics declared" diff --git a/tests/010.phpt b/tests/010.phpt index 8491931..abb7764 100644 --- a/tests/010.phpt +++ b/tests/010.phpt @@ -29,16 +29,16 @@ var_dump(uopz_get_hook("none")); var_dump(uopz_get_hook(DateTime::class, "__construct")); ?> ---EXPECT-- +--EXPECTF-- bool(true) -object(Closure)#1 (1) { +object(Closure)#1 (%d) {%A ["parameter"]=> array(1) { ["$arg"]=> string(10) "" } } -object(Closure)#2 (0) { +object(Closure)#2 (%d) {%A } NULL NULL diff --git a/tests/012.phpt b/tests/012.phpt index 6dd1b6d..246122d 100644 --- a/tests/012.phpt +++ b/tests/012.phpt @@ -11,7 +11,7 @@ class Foo { public function exists() {} } -uopz_add_function(Foo::class, "METHOD", /** doc **/ function(Type $type = null, $with = null, $args = null, ... $vars) : bool { +uopz_add_function(Foo::class, "METHOD", /** doc **/ function(Type|null $type = null, $with = null, $args = null, ... $vars) : bool { return $this->priv(true); }); diff --git a/tests/017.phpt b/tests/017.phpt index f63d433..074faec 100644 --- a/tests/017.phpt +++ b/tests/017.phpt @@ -1,5 +1,14 @@ --TEST-- uopz_redefine +--SKIPIF-- + --EXTENSIONS-- uopz --INI-- diff --git a/tests/018.phpt b/tests/018.phpt index 2cb89ac..6715792 100644 --- a/tests/018.phpt +++ b/tests/018.phpt @@ -1,5 +1,14 @@ --TEST-- uopz_undefine +--SKIPIF-- + --EXTENSIONS-- uopz --INI-- diff --git a/tests/bugs/0006-uopz-opcache-const-subst.phpt b/tests/bugs/0006-uopz-opcache-const-subst.phpt index cfd5126..dee386f 100644 --- a/tests/bugs/0006-uopz-opcache-const-subst.phpt +++ b/tests/bugs/0006-uopz-opcache-const-subst.phpt @@ -7,6 +7,12 @@ uopz uopz_allow_exit(true); $opcache = ini_get("opcache.enable_cli"); if ($opcache === false || $opcache === "0") die("skip opcache required"); + + $protect = extension_loaded("Zend OPcache") + && ($conf = opcache_get_configuration()["directives"]) + && array_key_exists("opcache.protect_memory", $conf) + && $conf["opcache.protect_memory"]; + if ($protect) die("xfail known issues with constant redefinition; see #151"); ?> --INI-- uopz.disable=0 diff --git a/tests/bugs/gh167.phpt b/tests/bugs/gh167.phpt new file mode 100644 index 0000000..97aa302 --- /dev/null +++ b/tests/bugs/gh167.phpt @@ -0,0 +1,17 @@ +--TEST-- +uopz_set_return() overload confusion +--EXTENSIONS-- +uopz +--INI-- +uopz.disable=0 +--FILE-- + +--EXPECT-- +int(4711) diff --git a/tests/bugs/gh179.phpt b/tests/bugs/gh179.phpt new file mode 100644 index 0000000..9fa1adb --- /dev/null +++ b/tests/bugs/gh179.phpt @@ -0,0 +1,17 @@ +--TEST-- +uopz_set_static() does not check that $static is an array +--EXTENSIONS-- +uopz +--INI-- +uopz.disable=0 +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught InvalidArgumentException: unexpected parameter combination, expected (class, function, statics) or (function, statics) in %s:%d +%A diff --git a/tests/bugs/gh53.phpt b/tests/bugs/gh53.phpt index 5130048..2025977 100644 --- a/tests/bugs/gh53.phpt +++ b/tests/bugs/gh53.phpt @@ -2,6 +2,15 @@ github #53 --DESCRIPTION-- uopz_redefine() refuses to redefine a constant as array +--SKIPIF-- + --EXTENSIONS-- uopz --INI-- diff --git a/tests/bugs/gh99.phpt b/tests/bugs/gh99.phpt index 830d9cd..ab20280 100644 --- a/tests/bugs/gh99.phpt +++ b/tests/bugs/gh99.phpt @@ -23,9 +23,9 @@ var_dump(Stub()); var_dump($a); ?> ---EXPECT-- +--EXPECTF-- string(11) "hook called" int(123) -object(Closure)#1 (0) { +object(Closure)#1 (%d) {%A } diff --git a/uopz.c b/uopz.c index 2862125..936f759 100644 --- a/uopz.c +++ b/uopz.c @@ -197,6 +197,7 @@ static PHP_FUNCTION(uopz_set_return) uopz_disabled_guard(); if (uopz_parse_parameters("CSz|b", &clazz, &function, &variable, &execute) != SUCCESS && + !((clazz = NULL)) && uopz_parse_parameters("Sz|b", &function, &variable, &execute) != SUCCESS) { uopz_refuse_parameters( "unexpected parameter combination, expected (class, function, variable [, execute]) or (function, variable [, execute])"); @@ -334,8 +335,8 @@ static PHP_FUNCTION(uopz_set_static) uopz_disabled_guard(); - if (uopz_parse_parameters("CSz", &clazz, &function, &statics) != SUCCESS && - uopz_parse_parameters("Sz", &function, &statics) != SUCCESS) { + if (uopz_parse_parameters("CSa", &clazz, &function, &statics) != SUCCESS && + uopz_parse_parameters("Sa", &function, &statics) != SUCCESS) { uopz_refuse_parameters( "unexpected parameter combination, expected (class, function, statics) or (function, statics)"); return;