Skip to content

Commit 27dfb45

Browse files
committed
Fix json bindings on apache reload
Signed-off-by: Bob Weinand <[email protected]>
1 parent 610fb2b commit 27dfb45

File tree

10 files changed

+90
-1
lines changed

10 files changed

+90
-1
lines changed

appsec/src/extension/ddappsec.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#include "tags.h"
4242
#include "user_tracking.h"
4343

44+
#include <json/json.h>
45+
4446
#if ZTS
4547
static atomic_int _thread_count;
4648
#endif
@@ -171,10 +173,12 @@ static PHP_GSHUTDOWN_FUNCTION(ddappsec)
171173
if (prev == 1) {
172174
dd_log_shutdown();
173175
zai_config_mshutdown();
176+
zai_json_shutdown_bindings();
174177
}
175178
#else
176179
dd_log_shutdown();
177180
zai_config_mshutdown();
181+
zai_json_shutdown_bindings();
178182
#endif
179183

180184
memset(ddappsec_globals, '\0', sizeof(*ddappsec_globals)); // NOLINT

ext/ddtrace.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,7 @@ static PHP_MSHUTDOWN_FUNCTION(ddtrace) {
995995

996996
if (DDTRACE_G(disable) == 1) {
997997
zai_config_mshutdown();
998+
zai_json_shutdown_bindings();
998999
return SUCCESS;
9991000
}
10001001

@@ -1021,6 +1022,7 @@ static PHP_MSHUTDOWN_FUNCTION(ddtrace) {
10211022
ddtrace_shutdown_span_sampling_limiter();
10221023
ddtrace_limiter_destroy();
10231024
zai_config_mshutdown();
1025+
zai_json_shutdown_bindings();
10241026

10251027
ddtrace_user_req_shutdown();
10261028

profiling/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,9 +839,10 @@ extern "C" fn shutdown(_extension: *mut ZendExtension) {
839839
// data race condition.
840840
unsafe { config::shutdown() };
841841

842-
// SAFETY: zai_config_mshutdown should be safe to cal in shutdown instead
842+
// SAFETY: zai_config_mshutdown should be safe to call in shutdown instead
843843
// of mshutdown.
844844
unsafe { bindings::zai_config_mshutdown() };
845+
unsafe { bindings::zai_json_shutdown_bindings() };
845846
}
846847

847848
/// Notifies the profiler a trace has finished so it can update information

profiling/src/php_ffi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
// Profiling needs ZAI config for INI support.
1919
#include <config/config.h>
20+
// And json to cleanup json state for graceful restart
21+
#include <json/json.h>
2022

2123
// Used to communicate strings from C -> Rust.
2224
#include <zai_string/string.h>

tests/Common/WebFrameworkTestCase.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ private static function tearDownWebServer()
140140
}
141141
}
142142

143+
protected function reloadAppServer()
144+
{
145+
if (\method_exists(self::$appServer, "reload")) {
146+
self::$appServer->reload();
147+
} else {
148+
$this->markTestSkipped("Webserver reload not supported");
149+
}
150+
}
151+
143152
/**
144153
* Executed a call to the test web server.
145154
*
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
4+
use DDTrace\Tests\Common\SpanAssertion;
5+
use DDTrace\Tests\Common\WebFrameworkTestCase;
6+
use DDTrace\Tests\Frameworks\Util\Request\GetSpec;
7+
8+
final class ApacheReloadTest extends WebFrameworkTestCase
9+
{
10+
protected static function getAppIndexScript()
11+
{
12+
return __DIR__ . '/../../../Frameworks/Custom/Version_Not_Autoloaded/index.php';
13+
}
14+
15+
protected static function getEnvs()
16+
{
17+
return array_merge(parent::getEnvs(), [
18+
'APP_NAME' => 'custom_no_autoloaded_app',
19+
'DD_TRACE_NO_AUTOLOADER' => 'true',
20+
]);
21+
}
22+
23+
public function testWebserverReload()
24+
{
25+
$traces = $this->tracesFromWebRequest(function () {
26+
$this->call(GetSpec::create('A web request to a framework not using auto loaders', '/'));
27+
});
28+
29+
$this->assertSpans($traces, [
30+
SpanAssertion::exists('web.request'),
31+
]);
32+
33+
$this->reloadAppServer();
34+
35+
$traces = $this->tracesFromWebRequest(function () {
36+
$this->call(GetSpec::create('A web request to a framework not using auto loaders', '/'));
37+
});
38+
39+
$this->assertSpans($traces, [
40+
SpanAssertion::exists('web.request'),
41+
]);
42+
}
43+
}

tests/Sapi/PhpApache/PhpApache.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ public function start()
149149
$this->configChanged = false;
150150
}
151151

152+
public function reload()
153+
{
154+
$this->process->signal(SIGUSR1);
155+
usleep(10000);
156+
}
157+
152158
public function stop()
153159
{
154160
// I do not understand why we get a SIGTERM when we try to send a SIGTERM to apache.

tests/WebServer.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DDTrace\Tests\Sapi\PhpFpm\PhpFpm;
1010
use DDTrace\Tests\Sapi\Roadrunner\RoadrunnerServer;
1111
use DDTrace\Tests\Sapi\Sapi;
12+
use PHPUnit\Framework\Assert;
1213

1314
/**
1415
* A controllable php server running in a separate process.
@@ -180,6 +181,15 @@ public function start()
180181
usleep(500000);
181182
}
182183

184+
public function reload()
185+
{
186+
if (\method_exists($this->sapi, "reload")) {
187+
$this->sapi->reload();
188+
} else {
189+
Assert::markTestSkipped("Webserver reload not supported");
190+
}
191+
}
192+
183193
/**
184194
* Teardown promptly.
185195
*/

zend_abstract_interface/json/json.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ __attribute__((weak)) int php_json_encode(smart_str *buf, zval *val, int options
8989
__attribute__((weak)) zend_class_entry *php_json_serializable_ce;
9090
#endif
9191

92+
static bool zai_json_dynamic_bindings = false;
93+
9294
bool zai_json_setup_bindings(void) {
9395
if (php_json_encode && php_json_serializable_ce) {
9496
zai_json_encode = php_json_encode;
@@ -105,6 +107,8 @@ bool zai_json_setup_bindings(void) {
105107

106108
if (!json_me) return false;
107109

110+
zai_json_dynamic_bindings = true;
111+
108112
zai_json_encode = DL_FETCH_SYMBOL(json_me->handle, "php_json_encode");
109113
if (zai_json_encode == NULL) {
110114
zai_json_encode = DL_FETCH_SYMBOL(json_me->handle, "_php_json_encode");
@@ -138,6 +142,13 @@ bool zai_json_setup_bindings(void) {
138142
return zai_json_encode != NULL;
139143
}
140144

145+
void zai_json_shutdown_bindings(void) {
146+
if (zai_json_dynamic_bindings) {
147+
zai_json_dynamic_bindings = false;
148+
php_json_serializable_ce = NULL;
149+
}
150+
}
151+
141152
void zai_json_release_persistent_array(HashTable *ht) {
142153
#if PHP_VERSION_ID < 70300
143154
if (--GC_REFCOUNT(ht) == 0)

zend_abstract_interface/json/json.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ extern __attribute__((weak)) zend_class_entry *php_json_serializable_ce;
4545
void zai_json_release_persistent_array(HashTable *ht);
4646
void zai_json_dtor_pzval(zval *pval);
4747
bool zai_json_setup_bindings(void);
48+
void zai_json_shutdown_bindings(void);
4849

4950
#endif // ZAI_JSON_H

0 commit comments

Comments
 (0)