From 11017e000e961f99db38bf8ec1a1b520dc5213c3 Mon Sep 17 00:00:00 2001 From: NoiseByNorthwest Date: Tue, 3 Sep 2024 10:42:46 +0200 Subject: [PATCH 1/8] Add subnet mask support for IP matching --- README.md | 5 ++- src/php_spx.c | 9 +---- src/spx_utils.c | 60 ++++++++++++++++++++++++++++++ src/spx_utils.h | 2 + tests/spx_auth_ip_subnet_ko_1.phpt | 23 ++++++++++++ tests/spx_auth_ip_subnet_ko_2.phpt | 23 ++++++++++++ tests/spx_auth_ip_subnet_ko_3.phpt | 23 ++++++++++++ tests/spx_auth_ip_subnet_ok.phpt | 45 ++++++++++++++++++++++ 8 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 tests/spx_auth_ip_subnet_ko_1.phpt create mode 100644 tests/spx_auth_ip_subnet_ko_2.phpt create mode 100644 tests/spx_auth_ip_subnet_ko_3.phpt create mode 100644 tests/spx_auth_ip_subnet_ok.phpt diff --git a/README.md b/README.md index 4adfb8a..c0403bc 100644 --- a/README.md +++ b/README.md @@ -260,8 +260,8 @@ while ($task = get_next_ready_task()) { | _spx.http_enabled_ | `0` | _PHP_INI_SYSTEM_ | Whether to enable web UI and HTTP request profiling. | | _spx.http_key_ | | _PHP_INI_SYSTEM_ | The secret key used for authentication (see [security concern](#security-concern) for more details). You can use the following command to generate a 16 bytes random key as an hex string: `openssl rand -hex 16`. | | _spx.http_ip_var_ | `REMOTE_ADDR` | _PHP_INI_SYSTEM_ | The `$_SERVER` key holding the client IP address used for authentication (see [security concern](#security-concern) for more details). Overriding the default value is required when your application is behind a reverse proxy. | -| _spx.http_trusted_proxies_ | `127.0.0.1` | _PHP_INI_SYSTEM_ | The trusted proxy list as a comma separated list of IP addresses. This setting is ignored when `spx.http_ip_var`'s value is `REMOTE_ADDR`. | -| _spx.http_ip_whitelist_ | | _PHP_INI_SYSTEM_ | The IP address white list used for authentication as a comma separated list of IP addresses, use `*` to allow all IP addresses. | +| _spx.http_trusted_proxies_ | `127.0.0.1` | _PHP_INI_SYSTEM_ | The trusted proxy list as a comma separated list of IP addresses*. This setting is ignored when `spx.http_ip_var`'s value is `REMOTE_ADDR`. | +| _spx.http_ip_whitelist_ | | _PHP_INI_SYSTEM_ | The IP address white list used for authentication as a comma separated list of IP addresses*. | | _spx.http_ui_assets_dir_ | `/usr/local/share/misc/php-spx/assets/web-ui` | _PHP_INI_SYSTEM_ | The directory where the [web UI](#web-ui) files are installed. In most cases you do not have to change it. | | _spx.http_profiling_enabled_ | _NULL_ | _PHP_INI_SYSTEM_ | The INI level counterpart of the `SPX_ENABLED` parameter, for HTTP requests only. See [here for more details](#available-parameters). | | _spx.http_profiling_auto_start_ | _NULL_ | _PHP_INI_SYSTEM_ | The INI level counterpart of the `SPX_AUTO_START` parameter, for HTTP requests only. See [here for more details](#available-parameters). | @@ -270,6 +270,7 @@ while ($task = get_next_ready_task()) { | _spx.http_profiling_depth_ | _NULL_ | _PHP_INI_SYSTEM_ | The INI level counterpart of the `SPX_DEPTH` parameter, for HTTP requests only. See [here for more details](#available-parameters). | | _spx.http_profiling_metrics_ | _NULL_ | _PHP_INI_SYSTEM_ | The INI level counterpart of the `SPX_METRICS` parameter, for HTTP requests only. See [here for more details](#available-parameters). | +_\*: `*` (match all) and subnet masks (e.g. `192.168.1.0/24`) are supported._ #### Private environment diff --git a/src/php_spx.c b/src/php_spx.c index 13a31a0..f5a88b4 100644 --- a/src/php_spx.c +++ b/src/php_spx.c @@ -552,7 +552,7 @@ static int check_access(void) int found = 0; SPX_UTILS_TOKENIZE_STRING(SPX_G(http_trusted_proxies), ',', trusted_proxy_ip_str, 64, { - if (0 == strcmp(proxy_ip_str, trusted_proxy_ip_str)) { + if (spx_utils_ip_match(proxy_ip_str, trusted_proxy_ip_str)) { found = 1; } }); @@ -586,18 +586,13 @@ static int check_access(void) } SPX_UTILS_TOKENIZE_STRING(authorized_ips_str, ',', authorized_ip_str, 64, { - if (0 == strcmp(ip_str, authorized_ip_str)) { + if (spx_utils_ip_match(ip_str, authorized_ip_str)) { /* ip authorized (OK, as well as all previous checks) -> granted */ return 1; } }); - if (0 == strcmp(authorized_ips_str, "*")) { - /* all ips authorized */ - return 1; - } - spx_php_log_notice( "access not granted: \"%s\" IP is not in white list (\"%s\")", ip_str, diff --git a/src/spx_utils.c b/src/spx_utils.c index 7653c01..fe761e4 100644 --- a/src/spx_utils.c +++ b/src/spx_utils.c @@ -24,7 +24,67 @@ # include #endif +#include + #include "spx_utils.h" +#include "spx_php.h" + +int spx_utils_ip_match(const char * ip_address_str, const char * target) +{ + if ( + strcmp(target, "*") == 0 || + strcmp(target, ip_address_str) == 0 + ) { + return 1; + } + + // subnet handling + + const char * slash_ptr = strchr(target, '/'); + if (slash_ptr == NULL) { + return 0; + } + + const size_t slash_pos = slash_ptr - target; + if (! (7 <= slash_pos && slash_pos <= 15)) { + return 0; + } + + const size_t target_suffix_len = strlen(slash_ptr); + if (! (2 <= target_suffix_len && target_suffix_len <= 3)) { + return 0; + } + + char target_ip_address_str[32]; + strncpy(target_ip_address_str, target, sizeof target_ip_address_str); + target_ip_address_str[slash_pos] = 0; + + const in_addr_t target_ip_address = inet_addr(target_ip_address_str); + if (target_ip_address == INADDR_NONE) { + return 0; + } + + char target_mask_str[32]; + snprintf(target_mask_str, sizeof target_mask_str, "%s", slash_ptr + 1); + const long target_mask_bits = strtol(target_mask_str, NULL, 10); + + if (! (1 <= target_mask_bits && target_mask_bits <= 31)) { + return 0; + } + + const in_addr_t target_mask = (~0) << (32 - target_mask_bits); + + const in_addr_t ip_address = inet_addr(ip_address_str); + if (ip_address == INADDR_NONE) { + return 0; + } + + if ((ntohl(ip_address) & target_mask) == (ntohl(target_ip_address) & target_mask)) { + return 1; + } + + return 0; +} char * spx_utils_resolve_confined_file_absolute_path( const char * root_dir, diff --git a/src/spx_utils.h b/src/spx_utils.h index 0de1879..9154276 100644 --- a/src/spx_utils.h +++ b/src/spx_utils.h @@ -50,6 +50,8 @@ do { \ } \ } while (0) +int spx_utils_ip_match(const char * ip_address, const char * target); + char * spx_utils_resolve_confined_file_absolute_path( const char * root_dir, const char * relative_path, diff --git a/tests/spx_auth_ip_subnet_ko_1.phpt b/tests/spx_auth_ip_subnet_ko_1.phpt new file mode 100644 index 0000000..ebd68aa --- /dev/null +++ b/tests/spx_auth_ip_subnet_ko_1.phpt @@ -0,0 +1,23 @@ +--TEST-- +Authentication: KO (invalid IP address) +--CGI-- +--INI-- +spx.http_enabled=1 +spx.http_key="dev" +spx.http_ip_whitelist="10.0.0.0/24" +spx.http_ui_assets_dir="{PWD}/../assets/web-ui" +log_errors=on +--ENV-- +return << +--EXPECT-- +Notice: SPX: access not granted: "10.0.1.1" IP is not in white list ("10.0.0.0/24") in Unknown on line 0 +Normal output \ No newline at end of file diff --git a/tests/spx_auth_ip_subnet_ko_2.phpt b/tests/spx_auth_ip_subnet_ko_2.phpt new file mode 100644 index 0000000..c131634 --- /dev/null +++ b/tests/spx_auth_ip_subnet_ko_2.phpt @@ -0,0 +1,23 @@ +--TEST-- +Authentication: KO (invalid IP address) +--CGI-- +--INI-- +spx.http_enabled=1 +spx.http_key="dev" +spx.http_ip_whitelist="10.0.0.0/0" +spx.http_ui_assets_dir="{PWD}/../assets/web-ui" +log_errors=on +--ENV-- +return << +--EXPECT-- +Notice: SPX: access not granted: "10.0.0.1" IP is not in white list ("10.0.0.0/0") in Unknown on line 0 +Normal output \ No newline at end of file diff --git a/tests/spx_auth_ip_subnet_ko_3.phpt b/tests/spx_auth_ip_subnet_ko_3.phpt new file mode 100644 index 0000000..65a2f10 --- /dev/null +++ b/tests/spx_auth_ip_subnet_ko_3.phpt @@ -0,0 +1,23 @@ +--TEST-- +Authentication: KO (invalid IP address) +--CGI-- +--INI-- +spx.http_enabled=1 +spx.http_key="dev" +spx.http_ip_whitelist="10.0.0.0/32" +spx.http_ui_assets_dir="{PWD}/../assets/web-ui" +log_errors=on +--ENV-- +return << +--EXPECT-- +Notice: SPX: access not granted: "10.0.0.1" IP is not in white list ("10.0.0.0/32") in Unknown on line 0 +Normal output \ No newline at end of file diff --git a/tests/spx_auth_ip_subnet_ok.phpt b/tests/spx_auth_ip_subnet_ok.phpt new file mode 100644 index 0000000..7bbf297 --- /dev/null +++ b/tests/spx_auth_ip_subnet_ok.phpt @@ -0,0 +1,45 @@ +--TEST-- +Authentication: OK (valid IP address) +--CGI-- +--INI-- +spx.http_enabled=1 +spx.http_key="dev" +spx.http_ip_whitelist="10.0.0.0/24" +spx.http_ui_assets_dir="{PWD}/../assets/web-ui" +log_errors=on +--ENV-- +return << +--EXPECT-- +{"results": [ +{"key": "wt","short_name": "Wall time","name": "Wall time","type": "time","releasable": 0} +,{"key": "ct","short_name": "CPU time","name": "CPU time","type": "time","releasable": 0} +,{"key": "it","short_name": "Idle time","name": "Idle time","type": "time","releasable": 0} +,{"key": "zm","short_name": "ZE memory usage","name": "Zend Engine memory usage","type": "memory","releasable": 1} +,{"key": "zmac","short_name": "ZE alloc count","name": "Zend Engine allocation count","type": "quantity","releasable": 0} +,{"key": "zmab","short_name": "ZE alloc bytes","name": "Zend Engine allocated bytes","type": "memory","releasable": 0} +,{"key": "zmfc","short_name": "ZE free count","name": "Zend Engine free count","type": "quantity","releasable": 0} +,{"key": "zmfb","short_name": "ZE free bytes","name": "Zend Engine freed bytes","type": "memory","releasable": 0} +,{"key": "zgr","short_name": "ZE GC runs","name": "Zend Engine GC run count","type": "quantity","releasable": 0} +,{"key": "zgb","short_name": "ZE GC root buffer","name": "Zend Engine GC root buffer length","type": "quantity","releasable": 1} +,{"key": "zgc","short_name": "ZE GC collected","name": "Zend Engine GC collected cycle count","type": "quantity","releasable": 0} +,{"key": "zif","short_name": "ZE file count","name": "Zend Engine included file count","type": "quantity","releasable": 0} +,{"key": "zil","short_name": "ZE line count","name": "Zend Engine included line count","type": "quantity","releasable": 0} +,{"key": "zuc","short_name": "ZE class count","name": "Zend Engine user class count","type": "quantity","releasable": 0} +,{"key": "zuf","short_name": "ZE func. count","name": "Zend Engine user function count","type": "quantity","releasable": 0} +,{"key": "zuo","short_name": "ZE opcodes count","name": "Zend Engine user opcode count","type": "quantity","releasable": 0} +,{"key": "zo","short_name": "ZE object count","name": "Zend Engine object count","type": "quantity","releasable": 1} +,{"key": "ze","short_name": "ZE error count","name": "Zend Engine error count","type": "quantity","releasable": 0} +,{"key": "mor","short_name": "Own RSS","name": "Process's own RSS","type": "memory","releasable": 1} +,{"key": "io","short_name": "I/O Bytes","name": "I/O Bytes (reads + writes)","type": "memory","releasable": 0} +,{"key": "ior","short_name": "I/O Read Bytes","name": "I/O Read Bytes","type": "memory","releasable": 0} +,{"key": "iow","short_name": "I/O Written Bytes","name": "I/O Written Bytes","type": "memory","releasable": 0} +]} \ No newline at end of file From 64aecef348b9994bbb8a02c80bd53801f67fc888 Mon Sep 17 00:00:00 2001 From: Daniel Ruf Date: Sun, 22 Sep 2024 18:43:49 +0200 Subject: [PATCH 2/8] Keep scroll position in flatprofile view on repaint - closes #266 --- assets/web-ui/js/widget.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assets/web-ui/js/widget.js b/assets/web-ui/js/widget.js index ab97b58..4c4560f 100644 --- a/assets/web-ui/js/widget.js +++ b/assets/web-ui/js/widget.js @@ -572,9 +572,13 @@ class Widget { this.repaintTimeout = setTimeout( () => { + let initialScrollPos = 0; this.repaintTimeout = null; const id = this.container.attr('id'); + if (id === 'flatprofile') { + initialScrollPos = document.querySelector('#flatprofile > div').scrollTop; + } console.time('repaint ' + id); console.time('clear ' + id); this.clear(); @@ -583,6 +587,9 @@ class Widget { this.render(); console.timeEnd('render ' + id); console.timeEnd('repaint ' + id); + if (id === 'flatprofile') { + document.querySelector('#flatprofile > div').scrollTop = initialScrollPos; + } }, 0 ); From fc793d8c0ff61e0837a1f6e311b620fb0f075a3e Mon Sep 17 00:00:00 2001 From: NoiseByNorthwest Date: Sun, 29 Sep 2024 12:45:18 +0200 Subject: [PATCH 3/8] Add PHP8.4 support --- .github/workflows/main.yml | 2 +- README.md | 4 ++-- src/php_spx.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 190078b..d846891 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - php: [ '5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3' ] + php: [ '5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4' ] name: - linux diff --git a/README.md b/README.md index c0403bc..6e00582 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Current requirements are: * x86-64 or ARM64 * **GNU/Linux**, **macOS** or **FreeBSD** * zlib dev package (e.g. zlib1g-dev on Debian based distros) -* PHP 5.4 to 8.3 +* PHP 5.4 to 8.4 ## Installation @@ -503,7 +503,7 @@ See the [LICENSE][:link-license:] file for more information. [:badge-ci:]: https://github.com/NoiseByNorthwest/php-spx/actions/workflows/main.yml/badge.svg [:link-ci:]: https://github.com/NoiseByNorthwest/php-spx/actions/workflows/main.yml -[:badge-php-versions:]: https://img.shields.io/badge/php-5.4--8.3-blue.svg +[:badge-php-versions:]: https://img.shields.io/badge/php-5.4--8.4-blue.svg [:badge-supported-platforms:]: https://img.shields.io/badge/platform-GNU/Linux%20|%20macOS%20|%20FreeBSD%20-yellow [:badge-supported-arch:]: https://img.shields.io/badge/architecture-x86--64%20|%20ARM64%20-silver diff --git a/src/php_spx.h b/src/php_spx.h index 1ab17e1..006e92d 100644 --- a/src/php_spx.h +++ b/src/php_spx.h @@ -31,8 +31,8 @@ # error "Only x86-64 and ARM64 architectures are supported" #endif -#if ZEND_MODULE_API_NO < 20100525 || ZEND_MODULE_API_NO > 20230831 // 8.3-RC5 -# error "Only the following PHP versions are supported: 5.4 to 8.3" +#if ZEND_MODULE_API_NO < 20100525 || ZEND_MODULE_API_NO > 20240924 +# error "Only the following PHP versions are supported: 5.4 to 8.4" #endif #define PHP_SPX_EXTNAME "SPX" From 4bc381ed431f7a8d77f0c940b818592f62b2f619 Mon Sep 17 00:00:00 2001 From: NoiseByNorthwest Date: Sun, 29 Sep 2024 14:36:18 +0200 Subject: [PATCH 4/8] CI: update macos version --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d846891..3b1e272 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: # Debian (docker) - { name: debian, ts: 'nts', compiler: 'gcc', os: ubuntu-20.04 } # macOS - - { name: mac, ts: 'nts', compiler: 'clang', os: macos-12 } + - { name: mac, ts: 'nts', compiler: 'clang', os: macos-13 } steps: - uses: actions/checkout@v3 From fab08fe1acccee07224dadb8987bb5a3ec35b0a7 Mon Sep 17 00:00:00 2001 From: NoiseByNorthwest Date: Sun, 29 Sep 2024 23:52:53 +0200 Subject: [PATCH 5/8] Fix PHP8.4 build on macOS --- config.m4 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config.m4 b/config.m4 index 6b0898a..e6fc9a1 100644 --- a/config.m4 +++ b/config.m4 @@ -14,6 +14,12 @@ if test "$PHP_SPX" = "yes"; then CFLAGS="-Werror -Wall -O3 -pthread -std=gnu90" + if test "$(uname -s 2>/dev/null)" = "Darwin" + then + # see discussion here https://github.com/NoiseByNorthwest/php-spx/pull/270 + CFLAGS="$CFLAGS -Wno-typedef-redefinition" + fi + if test "$PHP_SPX_DEV" = "yes" then CFLAGS="$CFLAGS -g" From e16b24354771a4e3c8541dd89a6269d8e37d9772 Mon Sep 17 00:00:00 2001 From: NoiseByNorthwest Date: Mon, 30 Sep 2024 09:28:30 +0200 Subject: [PATCH 6/8] v0.4.17 --- CHANGELOG.md | 31 +++++++++++++++++++++---------- src/php_spx.h | 2 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 266d509..0fdd3f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [v0.4.16](https://github.com/NoiseByNorthwest/php-spx/compare/0.4.15...0.4.16) +## [v0.4.17](https://github.com/NoiseByNorthwest/php-spx/compare/v0.4.16...v0.4.17) + +### Added +- PHP 8.4 support [#270](https://github.com/NoiseByNorthwest/php-spx/pull/270) +- Subnet mask support for IP matching [#261](https://github.com/NoiseByNorthwest/php-spx/pull/261) +- ZTS PHP beta support [#260](https://github.com/NoiseByNorthwest/php-spx/pull/260) + +### Fixed +- Keep scroll position in flatprofile view on repaint [#267](https://github.com/NoiseByNorthwest/php-spx/pull/267) +- Improved confinement check for file access from WEB UI [#255](https://github.com/NoiseByNorthwest/php-spx/pull/255) + +## [v0.4.16](https://github.com/NoiseByNorthwest/php-spx/compare/v0.4.15...v0.4.16) ### Added - Local snapshots of jQuery & jscolor in order to remove the internet access dependency of the Web UI [#217](https://github.com/NoiseByNorthwest/php-spx/issues/217) @@ -12,12 +23,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fixed unconfined server file access from WEB UI [#251](https://github.com/NoiseByNorthwest/php-spx/issues/251) -## [v0.4.15](https://github.com/NoiseByNorthwest/php-spx/compare/0.4.14...0.4.15) +## [v0.4.15](https://github.com/NoiseByNorthwest/php-spx/compare/v0.4.14...v0.4.15) ### Added - Added Debian builds to github workflow [#222](https://github.com/NoiseByNorthwest/php-spx/pull/222) -- Added PHP8.3 support [#230](https://github.com/NoiseByNorthwest/php-spx/pull/230) -- Added PHP5.4 support [#227](https://github.com/NoiseByNorthwest/php-spx/pull/227) +- Added PHP 8.3 support [#230](https://github.com/NoiseByNorthwest/php-spx/pull/230) +- Added PHP 5.4 support [#227](https://github.com/NoiseByNorthwest/php-spx/pull/227) ### Fixed - Fixed ESM module imports in Web UI [#233](https://github.com/NoiseByNorthwest/php-spx/issues/233) @@ -25,7 +36,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed non-portable path expectation in tests [#221](https://github.com/NoiseByNorthwest/php-spx/pull/221) -## [v0.4.14](https://github.com/NoiseByNorthwest/php-spx/compare/0.4.13...0.4.14) +## [v0.4.14](https://github.com/NoiseByNorthwest/php-spx/compare/v0.4.13...v0.4.14) ### Added - Added simple search feature @@ -36,7 +47,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed buffer overflow in str_builder -## [v0.4.13](https://github.com/NoiseByNorthwest/php-spx/compare/0.4.12...0.4.13) +## [v0.4.13](https://github.com/NoiseByNorthwest/php-spx/compare/v0.4.12...v0.4.13) ### Added - Github Actions workflow ([#180](https://github.com/NoiseByNorthwest/php-spx/issues/180)) @@ -50,7 +61,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Travis CI [#195](https://github.com/NoiseByNorthwest/php-spx/issues/195) -## [v0.4.0](https://github.com/NoiseByNorthwest/php-spx/compare/0.3.0...0.4.0) +## [v0.4.0](https://github.com/NoiseByNorthwest/php-spx/compare/v0.3.0...v0.4.0) ### Added - Analysis screen: fix the NaNs in time grid when time goes above 1000s (fixes [#65](https://github.com/NoiseByNorthwest/php-spx/issues/65)) @@ -66,7 +77,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fix build on macOS 10.11- (fixes [#78](https://github.com/NoiseByNorthwest/php-spx/pull/78)) -## [v0.3.0](https://github.com/NoiseByNorthwest/php-spx/compare/0.2.0...0.3.0) +## [v0.3.0](https://github.com/NoiseByNorthwest/php-spx/compare/v0.2.0...v0.3.0) ### Added - Improve documentation around web UI requirements (fixes [#54](https://github.com/NoiseByNorthwest/php-spx/issues/54)) @@ -93,7 +104,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Web UI / analysis screen: improved layout -## [v0.2.0](https://github.com/NoiseByNorthwest/php-spx/compare/0.1.2...0.2.0) +## [v0.2.0](https://github.com/NoiseByNorthwest/php-spx/compare/v0.1.2...v0.2.0) ### Added - Add web UI ([#14](https://github.com/NoiseByNorthwest/php-spx/pull/14)) @@ -106,7 +117,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Remove Callgrind report type ([#11](https://github.com/NoiseByNorthwest/php-spx/issues/11)) -## [v0.1.2](https://github.com/NoiseByNorthwest/php-spx/compare/0.1.2...0.1.2) +## [v0.1.2](https://github.com/NoiseByNorthwest/php-spx/compare/v0.1.2...v0.1.2) ### Added - Add macOS support ([orls](https://github.com/orls) in [#13](https://github.com/NoiseByNorthwest/php-spx/pull/13)) diff --git a/src/php_spx.h b/src/php_spx.h index 006e92d..1a68449 100644 --- a/src/php_spx.h +++ b/src/php_spx.h @@ -36,6 +36,6 @@ #endif #define PHP_SPX_EXTNAME "SPX" -#define PHP_SPX_VERSION "0.4.16" +#define PHP_SPX_VERSION "0.4.17" extern zend_module_entry spx_module_entry; From b8dc02a50f6491ea9f79d75a3ef183b2798f20f2 Mon Sep 17 00:00:00 2001 From: NoiseByNorthwest Date: Sun, 24 Nov 2024 15:06:17 +0100 Subject: [PATCH 7/8] Make Zend MM custom handler state thread-local --- src/spx_php.c | 92 +++++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/src/spx_php.c b/src/spx_php.c index f68ca64..e3f1076 100644 --- a/src/spx_php.c +++ b/src/spx_php.c @@ -74,13 +74,6 @@ typedef void (*execute_internal_func_t) ( ); static struct { -#if ZEND_MODULE_API_NO >= 20151012 - void * (*malloc) (size_t size); - void (*free) (void * ptr); - void * (*realloc) (void * ptr, size_t size); - size_t (*block_size) (void * ptr); -#endif - #if ZEND_MODULE_API_NO < 20121212 void (*execute) (zend_op_array * op_array TSRMLS_DC); #else @@ -124,9 +117,6 @@ static struct { #endif ); } ze_hooked_func = { -#if ZEND_MODULE_API_NO >= 20151012 - NULL, NULL, NULL, NULL, -#endif NULL, NULL, NULL, NULL, NULL, #if ZEND_MODULE_API_NO >= 20151012 @@ -135,6 +125,23 @@ static struct { NULL }; +static SPX_THREAD_TLS struct { +#if ZEND_MODULE_API_NO >= 20151012 + void * (*malloc) (size_t size); + void (*free) (void * ptr); + void * (*realloc) (void * ptr, size_t size); + size_t (*block_size) (void * ptr); +#else + int unused; +#endif +} ze_tls_hooked_func = { +#if ZEND_MODULE_API_NO >= 20151012 + NULL, NULL, NULL, NULL +#else + 0 +#endif +}; + static SPX_THREAD_TLS struct { struct { struct { @@ -664,24 +671,28 @@ void spx_php_execution_init(void) #if ZEND_MODULE_API_NO >= 20151012 zend_mm_heap * ze_mm_heap = zend_mm_get_heap(); + /* + * FIXME document why we need ze_mm_custom_block_size instead of ze_mm_block_size + * when there is no previous MM custom handler. + */ + ze_tls_hooked_func.block_size = ze_mm_custom_block_size; + zend_mm_get_custom_handlers( ze_mm_heap, - &ze_hooked_func.malloc, - &ze_hooked_func.free, - &ze_hooked_func.realloc + &ze_tls_hooked_func.malloc, + &ze_tls_hooked_func.free, + &ze_tls_hooked_func.realloc ); - ze_hooked_func.block_size = ze_mm_custom_block_size; - if ( - !ze_hooked_func.malloc - || !ze_hooked_func.free - || !ze_hooked_func.realloc + !ze_tls_hooked_func.malloc + || !ze_tls_hooked_func.free + || !ze_tls_hooked_func.realloc ) { - ze_hooked_func.malloc = ze_mm_malloc; - ze_hooked_func.free = ze_mm_free; - ze_hooked_func.realloc = ze_mm_realloc; - ze_hooked_func.block_size = ze_mm_block_size; + ze_tls_hooked_func.malloc = ze_mm_malloc; + ze_tls_hooked_func.free = ze_mm_free; + ze_tls_hooked_func.realloc = ze_mm_realloc; + ze_tls_hooked_func.block_size = ze_mm_block_size; } zend_mm_set_custom_handlers( @@ -697,24 +708,24 @@ void spx_php_execution_shutdown(void) { #if ZEND_MODULE_API_NO >= 20151012 if ( - ze_hooked_func.malloc - && ze_hooked_func.free - && ze_hooked_func.realloc + ze_tls_hooked_func.malloc + && ze_tls_hooked_func.free + && ze_tls_hooked_func.realloc ) { zend_mm_heap * ze_mm_heap = zend_mm_get_heap(); if ( /* - * ze_hooked_func.malloc was defaulted to ze_mm_malloc only if there were no + * ze_tls_hooked_func.malloc was defaulted to ze_mm_malloc only if there were no * previous custom handlers. */ - ze_hooked_func.malloc != ze_mm_malloc + ze_tls_hooked_func.malloc != ze_mm_malloc ) { zend_mm_set_custom_handlers( ze_mm_heap, - ze_hooked_func.malloc, - ze_hooked_func.free, - ze_hooked_func.realloc + ze_tls_hooked_func.malloc, + ze_tls_hooked_func.free, + ze_tls_hooked_func.realloc ); } else { /* @@ -733,9 +744,10 @@ void spx_php_execution_shutdown(void) } } - ze_hooked_func.malloc = NULL; - ze_hooked_func.free = NULL; - ze_hooked_func.realloc = NULL; + ze_tls_hooked_func.malloc = NULL; + ze_tls_hooked_func.free = NULL; + ze_tls_hooked_func.realloc = NULL; + ze_tls_hooked_func.block_size = NULL; } #endif @@ -1013,11 +1025,11 @@ static void * ze_mm_realloc(void * ptr, size_t size) static void * tls_hook_malloc(size_t size) { - void * ptr = ze_hooked_func.malloc(size); + void * ptr = ze_tls_hooked_func.malloc(size); if (ptr) { context.alloc_count++; - context.alloc_bytes += ze_hooked_func.block_size(ptr); + context.alloc_bytes += ze_tls_hooked_func.block_size(ptr); } return ptr; @@ -1027,17 +1039,17 @@ static void tls_hook_free(void * ptr) { if (ptr) { context.free_count++; - context.free_bytes += ze_hooked_func.block_size(ptr); + context.free_bytes += ze_tls_hooked_func.block_size(ptr); } - ze_hooked_func.free(ptr); + ze_tls_hooked_func.free(ptr); } static void * tls_hook_realloc(void * ptr, size_t size) { - const size_t old_size = ptr ? ze_hooked_func.block_size(ptr) : 0; - void * new = ze_hooked_func.realloc(ptr, size); - const size_t new_size = new ? ze_hooked_func.block_size(new) : 0; + const size_t old_size = ptr ? ze_tls_hooked_func.block_size(ptr) : 0; + void * new = ze_tls_hooked_func.realloc(ptr, size); + const size_t new_size = new ? ze_tls_hooked_func.block_size(new) : 0; if (ptr && new) { if (ptr != new) { From f36d4312d7c914b42520bccb242d769f9ed3626e Mon Sep 17 00:00:00 2001 From: NoiseByNorthwest Date: Sun, 24 Nov 2024 15:14:53 +0100 Subject: [PATCH 8/8] Fix tests for PHP5 --- src/spx_php.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/spx_php.c b/src/spx_php.c index e3f1076..12051cf 100644 --- a/src/spx_php.c +++ b/src/spx_php.c @@ -125,22 +125,16 @@ static struct { NULL }; -static SPX_THREAD_TLS struct { #if ZEND_MODULE_API_NO >= 20151012 +static SPX_THREAD_TLS struct { void * (*malloc) (size_t size); void (*free) (void * ptr); void * (*realloc) (void * ptr, size_t size); size_t (*block_size) (void * ptr); -#else - int unused; -#endif } ze_tls_hooked_func = { -#if ZEND_MODULE_API_NO >= 20151012 NULL, NULL, NULL, NULL -#else - 0 -#endif }; +#endif static SPX_THREAD_TLS struct { struct {