Skip to content

Added support for ZTS (Zend Thread Safety), including FrankenPHP support#355

Open
ioaniftimesei wants to merge 172 commits intomainfrom
zts-thread-safety-request-processor
Open

Added support for ZTS (Zend Thread Safety), including FrankenPHP support#355
ioaniftimesei wants to merge 172 commits intomainfrom
zts-thread-safety-request-processor

Conversation

@ioaniftimesei
Copy link
Contributor

@ioaniftimesei ioaniftimesei commented Nov 18, 2025

  • Updated RequestProcessor to manage instances with thread safety, supporting both NTS and ZTS modes.
  • Introduced CreateInstance and DestroyInstance functions for instance management.
  • Refactored existing function pointers to accept instance pointers, ensuring proper context handling.
  • Improved logging and error handling during initialization and configuration updates.
  • Added mutex locks to prevent race conditions in concurrent environments.
  • Adjusted various function signatures to accommodate instance pointers for better encapsulation of state.

Summary by Aikido

Security Issues: 0 🔍 Quality Issues: 11 ✅ Resolved Issues: 3

🚀 New Features

  • Added instance-based ZTS support and Create/Destroy instance functions

⚡ Enhancements

  • Updated GitHub workflows to build NTS and ZTS PHP extensions
  • Improved thread safety with mutexes, atomic operations, and logging

🔧 Refactors

  • Refactored code to propagate instance pointers across Go modules
  • Refactored PHP extension to remove globals and use per-instance state

More info

…readability and performance in multiple files
…ion,

so destroy the stats map after RequestProcessor to prevent use-after-free.
…ensure proper cleanup and prevent use-after-free issues.
- Updated RequestProcessor to manage instances with thread safety, supporting both NTS and ZTS modes.
- Introduced CreateInstance and DestroyInstance functions for instance management.
- Refactored existing function pointers to accept instance pointers, ensuring proper context handling.
- Improved logging and error handling during initialization and configuration updates.
- Added mutex locks to prevent race conditions in concurrent environments.
- Adjusted various function signatures to accommodate instance pointers for better encapsulation of state.
Comment on lines 82 to 135
@@ -104,10 +104,61 @@ jobs:

- name: Check PHP setup
run: |
which php
php -v
php -i
php -m | grep -E 'curl|mysqli' || (echo "Required extensions missing" && php -m && exit 1)
php -v | grep -v "ZTS" > /dev/null || (echo "ERROR: PHP is ZTS, expected NTS!" && php -v && exit 1)


- name: Build extension
run: |
rm -rf build
mkdir build
cd lib/php-extension
phpize
cd ../../build
CXX=g++ CXXFLAGS="-fPIC -g -O2 -I../lib/php-extension/include" LDFLAGS="-lstdc++" ../lib/php-extension/configure
make -j"$(nproc)"

- name: Version Aikido extension
run: |
cd ./build/modules
mv aikido.so ${{ env.AIKIDO_ARTIFACT }}-nts.so

- name: Archive build artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: ${{ env.AIKIDO_ARTIFACT }}-nts-${{ env.ARCH }}
if-no-files-found: error
path: |
${{ github.workspace }}/build/modules/${{ env.AIKIDO_ARTIFACT }}-nts.so
${{ github.workspace }}/tests/*.diff

build_php_extension_zts:
name: Build php${{ matrix.php_version }} extension ZTS ${{ matrix.arch == '' && 'x86_64' || 'arm' }}
runs-on: ubuntu-24.04${{ matrix.arch }}
container: ghcr.io/aikidosec/firewall-php-build-extension-zts:${{ matrix.php_version }}-v1
strategy:
matrix:
php_version: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
arch: [ '', '-arm' ]
fail-fast: false

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Get Arch
run: echo "ARCH=$(uname -m)" >> $GITHUB_ENV

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Comment on lines 609 to 521
uname -a
cat /etc/centos-release || cat /etc/redhat-release || echo "CentOS/Stream detected"
php -v
nginx -v || true
which php-fpm && php-fpm -v || true

- name: Verify ZTS is enabled
run: |
php -v | grep -q "ZTS" || (echo "ERROR: ZTS not enabled!" && exit 1)
php -v

- name: Install and start MySQL
run: |
mkdir -p /var/lib/mysql
mysqld --initialize-insecure --datadir=/var/lib/mysql
mysqld -u root --datadir=/var/lib/mysql --socket=/var/lib/mysql/mysql.sock &
sleep 10
mysql -u root -e "CREATE DATABASE IF NOT EXISTS db;"
mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'pwd'; FLUSH PRIVILEGES;"

- name: Test MySQL connection with mysqli
run: |
php -r '
$mysqli = new mysqli("localhost", "root", "pwd", "db");
if ($mysqli->connect_error) {
echo "MySQL connection failed: " . $mysqli->connect_error . "\n";
exit(1);
} else {
echo "MySQL connection successful\n";
$mysqli->close();
}
'

- name: Get Arch
run: echo "ARCH=$(uname -m)" >> $GITHUB_ENV

- name: Check PHP setup
run: |
uname -m
php -v
php -i | head -20

- name: Get Aikido version
run: |
AIKIDO_VERSION=$(grep '#define PHP_AIKIDO_VERSION' lib/php-extension/include/php_aikido.h | awk -F'"' '{print $2}')
echo $AIKIDO_VERSION
echo "AIKIDO_VERSION=$AIKIDO_VERSION" >> $GITHUB_ENV
echo "AIKIDO_RPM=aikido-php-firewall.${{ env.ARCH }}.rpm" >> $GITHUB_ENV

- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: |
${{ env.AIKIDO_RPM }}

- name: Install RPM
run: |
rpm -Uvh --oldpackage ${{ env.AIKIDO_RPM }}/${{ env.AIKIDO_RPM }}

- name: Run CLI tests
run: |
export TEST_PHP_EXECUTABLE=/usr/local/bin/php
php lib/php-extension/run-tests.php ./tests/cli

- name: Run ${{ matrix.server }} server tests
run: |

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 22 days ago

To fix this, explicitly restrict the GITHUB_TOKEN permissions for the workflow so it doesn’t inherit potentially read‑write defaults. The best way, without changing behavior, is to add a workflow‑level permissions: block granting only contents: read, which is sufficient for typical read operations (e.g., checking out code). Since we are only allowed to modify the shown .github/workflows/build.yml snippet and there is no global permissions: block visible, we will add permissions: contents: read to each of the relevant jobs. Concretely:

  • In .github/workflows/build.yml, for each job definition in the shown snippet that lacks permissions:, add a permissions: mapping immediately under the job header (after runs-on or needs/strategy keys, but still within the job).
  • For the test_php_ubuntu, test_php_ubuntu_zts, test_php_centos, and test_php_centos_zts jobs shown or referenced, add:
permissions:
  contents: read

These jobs only run commands in containers and download artifacts, so restricting to contents: read will not remove any required capability.

Suggested changeset 1
.github/workflows/build.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -382,6 +382,8 @@
   test_php_centos:
     name: CentOS NTS php-${{ matrix.php_version }} ${{ matrix.server }} ${{ matrix.arch == '' && 'x86_64' || 'arm' }}
     runs-on: ubuntu-24.04${{ matrix.arch }}
+    permissions:
+      contents: read
     container:
       image: ghcr.io/aikidosec/firewall-php-test-centos-nts:${{ matrix.php_version }}-v2
       options: --privileged
@@ -471,6 +473,8 @@
   test_php_ubuntu:
     name: Ubuntu NTS php-${{ matrix.php_version }} ${{ matrix.server }} ${{ matrix.arch == '' && 'x86_64' || 'arm' }}
     runs-on: ubuntu-24.04${{ matrix.arch }}
+    permissions:
+      contents: read
     container:
       image: ghcr.io/aikidosec/firewall-php-test-ubuntu-nts:${{ matrix.php_version }}-v2
       options: --privileged
@@ -540,6 +544,8 @@
   test_php_ubuntu_zts:
     name: Ubuntu ZTS php-${{ matrix.php_version }} ${{ matrix.server }} ${{ matrix.arch == '' && 'x86_64' || 'arm' }}
     runs-on: ubuntu-24.04${{ matrix.arch }}
+    permissions:
+      contents: read
     container:
       image: ghcr.io/aikidosec/firewall-php-test-ubuntu-zts:${{ matrix.php_version }}-v2
       options: --privileged
EOF
@@ -382,6 +382,8 @@
test_php_centos:
name: CentOS NTS php-${{ matrix.php_version }} ${{ matrix.server }} ${{ matrix.arch == '' && 'x86_64' || 'arm' }}
runs-on: ubuntu-24.04${{ matrix.arch }}
permissions:
contents: read
container:
image: ghcr.io/aikidosec/firewall-php-test-centos-nts:${{ matrix.php_version }}-v2
options: --privileged
@@ -471,6 +473,8 @@
test_php_ubuntu:
name: Ubuntu NTS php-${{ matrix.php_version }} ${{ matrix.server }} ${{ matrix.arch == '' && 'x86_64' || 'arm' }}
runs-on: ubuntu-24.04${{ matrix.arch }}
permissions:
contents: read
container:
image: ghcr.io/aikidosec/firewall-php-test-ubuntu-nts:${{ matrix.php_version }}-v2
options: --privileged
@@ -540,6 +544,8 @@
test_php_ubuntu_zts:
name: Ubuntu ZTS php-${{ matrix.php_version }} ${{ matrix.server }} ${{ matrix.arch == '' && 'x86_64' || 'arm' }}
runs-on: ubuntu-24.04${{ matrix.arch }}
permissions:
contents: read
container:
image: ghcr.io/aikidosec/firewall-php-test-ubuntu-zts:${{ matrix.php_version }}-v2
options: --privileged
Copilot is powered by AI and may make mistakes. Always verify output.

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 22 days ago

To fix the problem, the workflow should explicitly set minimal GITHUB_TOKEN permissions instead of inheriting repository defaults. The simplest and safest approach is to add a permissions: block at the top (root) level of .github/workflows/build.yml, right under name: Build and before the on: section. This root-level block will apply to all jobs in the workflow that do not define their own permissions: block, which is the case for the jobs shown (including test_php_ubuntu_zts at line 540). Because the jobs use actions/checkout and actions/download-artifact and do not need to write to the repository or manage issues, we can limit permissions to contents: read, which is compatible with both of those actions.

Concretely:

  • Edit .github/workflows/build.yml.
  • Insert a root-level permissions: mapping after line 1 (name: Build) and before the existing on: block.
  • Set contents: read inside this block to grant only read access to the repository contents.
  • No other file or line changes are required; no new imports or actions are needed.
Suggested changeset 1
.github/workflows/build.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,5 +1,8 @@
 name: Build
 
+permissions:
+  contents: read
+
 on:
   push:
     branches:
EOF
@@ -1,5 +1,8 @@
name: Build

permissions:
contents: read

on:
push:
branches:
Copilot is powered by AI and may make mistakes. Always verify output.
}
tid := inst.GetThreadID()
// Create new event context if it doesn't exist
newCtx := &EventContextData{}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@ioaniftimesei ioaniftimesei force-pushed the zts-thread-safety-request-processor branch from 11b99c1 to ce92b16 Compare January 15, 2026 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FrankenPHP support

2 participants