ホームページ >php教程 >php手册 >PHP ストリームが時間内にシーンをクリーンアップできず、コア バグが発生しました

PHP ストリームが時間内にシーンをクリーンアップできず、コア バグが発生しました

WBOY
WBOYオリジナル
2016-06-21 08:52:421560ブラウズ

同僚は、set_error_handler を使用すると 100% 再現できるコアを見つけました。洗練された再現コードは次のとおりです (インターネットにアクセスできない環境である必要があります)。

関数 err_handler(){

終了;

true を返します;

}

set_error_handler('err_handler');

$client = file_get_contents("http://www.laruence.com/ServiceNoWse.asmx?WSDL");

Web サーバーに配置されたこのコードは、最初にアクセスされたときには正常に動作し、2 回目と 3 回目にはコアが表示されます。

gdb の追跡後、コアが php_stream_display_wrapper_errors 関数内にあることが判明しました。err_stack でエラー メッセージ文字列を処理すると、コア スタックは次のようになりました。

#0 0x000000302af6ff20 in strlen () /lib64/tls/libc.so.6

#1 0x0000002a989d97c1 in php_stream_display_wrapper_errors (wrapper=0x2a98e884a0、path=変数 "path" は使用できません。

) /home/huixc/package/php-5.2.14/main/streams/streams.c:151

#2 0x0000002a989dca22 _php_stream_open_wrapper_ex 内 (path=0x76e7c8 "http://www.laruence.com/ServiceNoWse.asmx?WSDL", mode=0x2a98ae3087 "rb", options=8,opened_pa​​th=0x0,

context=0x76e808) /home/huixc/package/php-5.2.14/main/streams/streams.c:1893

#3 0x0000002a98966541 in zif_file_get_contents (ht=-1729541984, return_value=0x76e738, return_value_ptr=変数「return_value_ptr」は使用できません。

) /home/huixc/package/php-5.2.14/ext/standard/file.c:541

#4 zend_do_fcall_common_helper_SPEC (execute_data=0x7fffffca30) の 0x0000002a98a2c05e (/home/huixc/package/php-5.2.14/Zend/zend_vm_execute.h:200

)

#5 0x0000002a98a2b671 の実行 (op_array=0x769890) at /home/huixc/package/php-5.2.14/Zend/zend_vm_execute.h:92

#6 0x0000002a98a0c734 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/huixc/package/php-5.2.14/Zend/zend.c:1134

#7 0x0000002a989c965d php_execute_script (primary_file=0x7fbffff00) at /home/huixc/package/php-5.2.14/main/main.c:2036

#8 0x0000002a98a9bd36 php_handler (r=0x8f1ba8) (/home/huixc/package/php-5.2.14/sapi/apache2handler/sapi_apache2.c:639

)

30分以上追跡した結果、ついにその理由が分かりました

これは、PHP では、終了の場合、ユーザー スクリプトが終了した後の最終作業を達成するために実際に set/longjmp が使用され、エラー コードの場合、出力されるエラー メッセージの数がラッパーの err_count に基づいて決定されるためです。

そして、エラーメッセージを出力した後、ラップエラーメッセージをクリアし、エラーカウントをゼロに設定します。

void php_stream_tidy_wrapper_error_log(php_stream_wrapper *ラッパー TSRMLS_DC)

{

if (ラッパー) {

/* エラースタックを整理します */

int i;

for (i = 0; i err_count; i++) {

efree(wrapper->err_stack[i]);

}

if (ラッパー->err_stack) {

efree(wrapper->err_stack);

}

ラッパー->err_stack = NULL;

ラッパー->err_count = 0;

}

}

ただし、エラーメッセージが表示された後、すぐに php_error_docref1 がトリガーされ、その後、コード内で設定された error_handler がトリガーされますが、最終的に、longjmp は SOAP 処理時に設定されたジャンプポイントに到達します。これにより、ペアがスキップされるため、php_stream_tidy_wrapper_error_log が呼び出されるため、リクエストが 2 回目に行われるとき、err_count は正しくゼロに初期化されず、最後のリクエストのエラー数が維持されます。

したがって、エラーメッセージを出力するときは、

……

for (i = 0, l = 0; i err_count; i++) {

l += strlen(wrapper->err_stack[i]) //コアが切れています

if (i err_count - 1) {

l += ブレン;

}

}

当面は、この問題を解決するには、ストリームの php_stream_display_wrapper_errors 関数で php_error_docref1 を呼び出す前に、 php_stream_tidy_wrapper_error_log;

を使用します。



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。