Bug #74878 [Opn->Ana]: Data race in ZTS builds
| From: | nikic@php.net | Date: | Fri, 07 Jul 2017 20:24:44 +0000 |
| Subject: | Bug #74878 [Opn->Ana]: Data race in ZTS builds | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-209910@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=74878&edit=1
ID: 74878
Updated by: nikic@php.net
Reported by: maroszek at gmx dot net
Summary: Data race in ZTS builds
-Status: Open
+Status: Analyzed
Type: Bug
Package: *General Issues
Operating System: Linux/MacOS
PHP Version: 7.2.0alpha3
Block user comment: N
Private report: N
New Comment:
The problem is that https://github.com/php/php-src/blob/master/Zend/zend_API.c#L3758
uses the original
name instead of the interned property_info->name.
Previous Comments:
------------------------------------------------------------------------
[2017-07-07 20:11:29] maroszek at gmx dot net
Description:
------------
Build PHP with thread sanitizer:
CFLAGS="-O1 -g -fsanitize=thread" ./configure --disable-fpm --disable-cgi --disable-cli
--disable-phpdbg --enable-embed=static --enable-maintainer-zts --without-iconv --enable-json
--enable-mbstring
Use my ZTS Embed example which produces a lot of parallel executed scripts.
https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7
Build it:
clang++ crash.cpp -Imain -ITSRM -IZend -I. --std=c++11 -Llibs -lphp7 -lxml2 -lresolv -ldl -pthread
-fsanitize=thread -g -O1
Run it:
./a.out
Background:
I am trying to locate random segfaults in PHP 7.2 since two weeks... and this is the best i could
find yet... (It is a lot better since 7.2! Thanks a lot!) Valgrind shows nothing... And this only
shows data races... but i cannot reproduce a crash :( Anyway... It should be fixed nevertheless.
Hopefully the data is useful :)
Hint:
Sometimes the data race happens in zend_destroy_hash. See second log from the output.
Test script:
---------------
<?
class JSONRPCException extends Exception {
//
}
class JSONRPC {
private $url;
private $username;
private $password;
function __construct($url) {
$data = @parse_url($url);
if(($data === false) || !isset($data['scheme']) || !isset($data['host']))
throw new Exception("Invalid URL");
$this->url = $data['scheme']."://".$data['host'];
if(isset($data['port']))
$this->url .= ":".$data['port'];
if(isset($data['path']))
$this->url .= $data['path'];
if(isset($data['user']))
$this->username = $data['user'];
else
$this->username = "";
if(isset($data['pass']))
$this->password = $data['pass'];
else
$this->password = "";
}
public function __call($method, $arguments) {
return self::makeRequest($this->url, $this->username, $this->password, $method,
$arguments, false);
}
static public function __callStatic($method, $params) {
return self::makeRequest("http://127.0.0.1:3777/api/", "",
"", $method, $params, true);
}
static private function makeRequest($url, $username, $password, $method, $params,
$customErrorHandler) {
try {
if (!is_scalar($method)) {
throw new Exception('Method name has no scalar value');
}
if (!is_array($params)) {
throw new Exception('Params must be given as array');
}
$id = round(fmod(microtime(true)*1000, 10000));
$params = array_values($params);
$strencode = function(&$item, $key) {
if ( is_string($item) )
$item = utf8_encode($item);
else if ( is_array($item) )
array_walk_recursive($item, $strencode);
};
array_walk_recursive($params, $strencode);
$request = Array(
"jsonrpc" => "2.0",
"method" => $method,
"params" => $params,
"id" => $id
);
$request = json_encode($request);
$header = "Content-type: application/json"."\r\n";
if(($username != "") || ($password != "")) {
$header .= "Authorization: Basic
".base64_encode($username.":".$password)."\r\n";
}
$options = Array(
"http" => array (
"method" => 'POST',
"header" => $header,
"content" => $request
)
);
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
if($response === false)
{
throw new Exception('Unable to connect');
}
if((strpos($http_response_header[0], "200") === false)) {
throw new Exception('Server did not respond successfully');
}
$response = json_decode($response, true);
if (is_null($response)) {
throw new Exception('Request error: No response');
}
$strdecode = function(&$item, $key) {
if ( is_string($item) )
$item = utf8_decode($item);
else if ( is_array($item) )
array_walk_recursive($item, $strdecode);
};
array_walk_recursive($response, $strdecode);
if (isset($response['error'])) {
throw new JSONRPCException($response['error']['message']);
}
if (!isset($response['id'])) {
throw new Exception('No response id');
} elseif ($response['id'] != $id) {
throw new Exception('Incorrect response id (request id: ' . $id . ', response
id: ' . $response['id'] . ')');
}
return $response['result'];
} catch (Exception $e) {
if($customErrorHandler) {
set_error_handler(array('JSONRPC', '__errorHandler'));
$trace = $e->getTrace();
trigger_error($e->getMessage().' in '.$trace[3]['file'].' on line
'.$trace[3]['line'], E_USER_WARNING);
restore_error_handler();
return false;
} else {
throw $e;
}
}
}
static private function __errorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno)) {
return;
}
echo $errstr;
return true;
}
}
?>
Expected result:
----------------
No output.
Actual result:
--------------
==================
WARNING: ThreadSanitizer: data race (pid=25837)
Write of size 4 at 0x7d0800009560 by thread T2:
#0 do_inherit_property zend_inheritance.c:709 (a.out+0x000100556bb4)
#1 zend_do_inheritance zend_inheritance.c:925 (a.out+0x0001005565b1)
#2 do_bind_inherited_class zend_compile.c:1183 (a.out+0x0001004a7bcd)
#3 zend_do_early_binding zend_compile.c:1240 (a.out+0x0001004a8279)
#4 zend_compile_top_stmt zend_compile.c:8080 (a.out+0x0001004bf1d1)
#5 zend_compile_top_stmt zend_compile.c:8068 (a.out+0x0001004bf116)
#6 zend_compile zend_language_scanner.l:601 (a.out+0x000100468c77)
#7 compile_file zend_language_scanner.l:635 (a.out+0x0001004688bf)
#8 phar_compile_file phar.c:3320 (a.out+0x0001002d76d5)
#9 zend_execute_scripts zend.c:1484 (a.out+0x0001004eb4c9)
#10 php_execute_script main.c:2550 (a.out+0x00010042c815)
#11 main::$_0::operator()() const crash.cpp:35 (a.out+0x000100001ae3)
#12 void* std::__1::__thread_proxy<std::__1::tuple<main::$_0> >(void*) thread:357
(a.out+0x0001000019c2)
Previous write of size 4 at 0x7d0800009560 by thread T1:
#0 do_inherit_property zend_inheritance.c:709 (a.out+0x000100556bb4)
#1 zend_do_inheritance zend_inheritance.c:925 (a.out+0x0001005565b1)
#2 do_bind_inherited_class zend_compile.c:1183 (a.out+0x0001004a7bcd)
#3 zend_do_early_binding zend_compile.c:1240 (a.out+0x0001004a8279)
#4 zend_compile_top_stmt zend_compile.c:8080 (a.out+0x0001004bf1d1)
#5 zend_compile_top_stmt zend_compile.c:8068 (a.out+0x0001004bf116)
#6 zend_compile zend_language_scanner.l:601 (a.out+0x000100468c77)
#7 compile_file zend_language_scanner.l:635 (a.out+0x0001004688bf)
#8 phar_compile_file phar.c:3320 (a.out+0x0001002d76d5)
#9 zend_execute_scripts zend.c:1484 (a.out+0x0001004eb4c9)
#10 php_execute_script main.c:2550 (a.out+0x00010042c815)
#11 main::$_0::operator()() const crash.cpp:35 (a.out+0x000100001ae3)
#12 void* std::__1::__thread_proxy<std::__1::tuple<main::$_0> >(void*) thread:357
(a.out+0x0001000019c2)
Location is heap block of size 32 at 0x7d0800009560 allocated by main thread:
#0 malloc <null>:144 (libclang_rt.tsan_osx_dynamic.dylib+0x00000004188a)
#1 __zend_malloc zend_alloc.c:2811 (a.out+0x0001004a213a)
#2 zend_declare_property zend_API.c:3766 (a.out+0x0001004fa0fe)
#3 zend_declare_property_string zend_API.c:3814 (a.out+0x0001004fa47a)
#4 zend_register_default_exception zend_exceptions.c:820 (a.out+0x00010052866c)
#5 zend_register_default_classes zend_default_classes.c:34 (a.out+0x0001005558f6)
#6 zm_startup_core zend_builtin_functions.c:302 (a.out+0x000100513bf1)
#7 zend_startup_module_ex zend_API.c:1873 (a.out+0x0001004f39e6)
#8 zend_startup_module_zval zend_API.c:1888 (a.out+0x0001004f41e1)
#9 zend_hash_apply zend_hash.c:1506 (a.out+0x00010050dda6)
#10 zend_startup_modules zend_API.c:1999 (a.out+0x0001004f4007)
#11 php_module_startup main.c:2269 (a.out+0x000100429f94)
#12 php_embed_startup php_embed.c:109 (a.out+0x0001006385f1)
#13 php_embed_init php_embed.c:200 (a.out+0x0001006388d2)
#14 main crash.cpp:10 (a.out+0x000100001209)
Thread T2 (tid=2628148, running) created by main thread at:
#0 pthread_create <null>:144 (libclang_rt.tsan_osx_dynamic.dylib+0x000000024410)
#1 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:369
(a.out+0x000100001936)
#2 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:365
(a.out+0x0001000018f0)
#3 std::__1::shared_ptr<std::__1::thread>
std::__1::shared_ptr<std::__1::thread>::make_shared<main::$_0>(main::$_0&&)
memory:3800 (a.out+0x0001000017b1)
#4 main crash.cpp:14 (a.out+0x00010000137a)
Thread T1 (tid=2628147, running) created by main thread at:
#0 pthread_create <null>:144 (libclang_rt.tsan_osx_dynamic.dylib+0x000000024410)
#1 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:369
(a.out+0x000100001936)
#2 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:365
(a.out+0x0001000018f0)
#3 std::__1::shared_ptr<std::__1::thread>
std::__1::shared_ptr<std::__1::thread>::make_shared<main::$_0>(main::$_0&&)
memory:3800 (a.out+0x0001000017b1)
#4 main crash.cpp:14 (a.out+0x00010000137a)
SUMMARY: ThreadSanitizer: data race zend_inheritance.c:709 in do_inherit_property
WARNING: ThreadSanitizer: data race (pid=50889)
Write of size 4 at 0x7d0800009560 by thread T1:
#0 zend_hash_destroy zend_hash.c:1268 (a.out+0x00010050cbcc)
#1 destroy_zend_class zend_opcode.c:309 (a.out+0x0001004d40a6)
#2 zend_hash_reverse_apply zend_hash.c:997 (a.out+0x00010050f926)
#3 shutdown_executor zend_execute_API.c:375 (a.out+0x0001004ca8dc)
#4 zend_deactivate zend.c:1060 (a.out+0x0001004e9ac6)
#5 php_request_shutdown main.c:1879 (a.out+0x000100428dc1)
#6 main::$_0::operator()() const crash.cpp:31 (a.out+0x0001000016ef)
#7 void* std::__1::__thread_proxy<std::__1::tuple<main::$_0> >(void*) thread:357
(a.out+0x0001000015c2)
Previous write of size 4 at 0x7d0800009560 by thread T3:
#0 do_inherit_property zend_inheritance.c:709 (a.out+0x0001005575d4)
#1 zend_do_inheritance zend_inheritance.c:925 (a.out+0x000100556fd1)
#2 do_bind_inherited_class zend_compile.c:1181 (a.out+0x0001004a79fd)
#3 zend_do_early_binding zend_compile.c:1238 (a.out+0x0001004a80a9)
#4 zend_compile_top_stmt zend_compile.c:8073 (a.out+0x0001004befa1)
#5 zend_compile_top_stmt zend_compile.c:8061 (a.out+0x0001004beee6)
#6 zend_compile zend_language_scanner.l:601 (a.out+0x000100468aa7)
#7 compile_file zend_language_scanner.l:635 (a.out+0x0001004686ef)
#8 phar_compile_file phar.c:3320 (a.out+0x0001002d7715)
#9 zend_execute_scripts zend.c:1531 (a.out+0x0001004eba39)
#10 php_execute_script main.c:2548 (a.out+0x00010042c715)
#11 main::$_0::operator()() const crash.cpp:35 (a.out+0x0001000016e3)
#12 void* std::__1::__thread_proxy<std::__1::tuple<main::$_0> >(void*) thread:357
(a.out+0x0001000015c2)
Location is heap block of size 32 at 0x7d0800009560 allocated by main thread:
#0 malloc <null>:144 (libclang_rt.tsan_osx_dynamic.dylib+0x00000004188a)
#1 __zend_malloc zend_alloc.c:2811 (a.out+0x0001004a1f6a)
#2 zend_declare_property zend_API.c:3746 (a.out+0x0001004fc30e)
#3 zend_declare_property_string zend_API.c:3794 (a.out+0x0001004fc68a)
#4 zend_register_default_exception zend_exceptions.c:820 (a.out+0x000100528d1c)
#5 zend_register_default_classes zend_default_classes.c:34 (a.out+0x000100556316)
#6 zm_startup_core zend_builtin_functions.c:302 (a.out+0x000100514301)
#7 zend_startup_module_ex zend_API.c:1873 (a.out+0x0001004f3f56)
#8 zend_startup_module_zval zend_API.c:1888 (a.out+0x0001004f4751)
#9 zend_hash_apply zend_hash.c:1507 (a.out+0x00010050e4b6)
#10 zend_startup_modules zend_API.c:1999 (a.out+0x0001004f4577)
#11 php_module_startup main.c:2269 (a.out+0x000100429e94)
#12 php_embed_startup php_embed.c:109 (a.out+0x0001006396b1)
#13 php_embed_init php_embed.c:200 (a.out+0x000100639992)
#14 main crash.cpp:10 (a.out+0x000100000e09)
Thread T1 (tid=2489677, running) created by main thread at:
#0 pthread_create <null>:144 (libclang_rt.tsan_osx_dynamic.dylib+0x000000024410)
#1 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:369
(a.out+0x000100001536)
#2 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:365
(a.out+0x0001000014f0)
#3 std::__1::shared_ptr<std::__1::thread>
std::__1::shared_ptr<std::__1::thread>::make_shared<main::$_0>(main::$_0&&)
memory:3800 (a.out+0x0001000013b1)
#4 main crash.cpp:14 (a.out+0x000100000f7a)
Thread T3 (tid=2489679, running) created by main thread at:
#0 pthread_create <null>:144 (libclang_rt.tsan_osx_dynamic.dylib+0x000000024410)
#1 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:369
(a.out+0x000100001536)
#2 std::__1::thread::thread<main::$_0, void>(main::$_0&&) thread:365
(a.out+0x0001000014f0)
#3 std::__1::shared_ptr<std::__1::thread>
std::__1::shared_ptr<std::__1::thread>::make_shared<main::$_0>(main::$_0&&)
memory:3800 (a.out+0x0001000013b1)
#4 main crash.cpp:14 (a.out+0x000100000f7a)
SUMMARY: ThreadSanitizer: data race zend_hash.c:1268 in zend_hash_destroy
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=74878&edit=1