Maison développement back-end tutoriel php 使用GDB调试PHP代码,解决PHP代码死循环问题_PHP

使用GDB调试PHP代码,解决PHP代码死循环问题_PHP

May 31, 2016 pm 01:16 PM
gdb 死循环 déboguer le code php

最近在帮同事解决Swoole Server问题时,发现有1个worker进程一直处于R的状态,而且CPU耗时非常高。初步断定是PHP代码中发生死循环。

下面通过一段代码展示如何解决PHP死循环问题。

代码如下:


#dead_loop.php
$array = array();
for($i = 0; $i {
    $array[] = $i;
}
include __DIR__."/include.php";
#include.php
while(1)
{
    usleep(10);
    $keys = array_flip($array);
    $index = array_search(rand(1500, 9999), $array);
    $str = str_repeat('A', $index);
    $strb = test($index, $str);
}
function test($index, $str)
{
    return str_replace('A', 'B', $str);
}

通过ps aux得到进程ID和状态如下,使用gdb -p 进程ptrace跟踪,通过bt命令得到调用栈

代码如下:


htf 3834 2.6 0.2 166676 22060 pts/12 R+ 10:50 0:12 php dead_loop.php
gdb -p 3834
(gdb) bt
#0 0x00000000008cc03f in zend_mm_check_ptr (heap=0x1eaa2c0, ptr=0x2584910, silent=1, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c",
__zend_lineno=182, __zend_orig_filename=0xee1888 "/home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c", __zend_orig_lineno=437)
at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:1485
#1 0x00000000008cd643 in _zend_mm_free_int (heap=0x1eaa2c0, p=0x2584910, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c", __zend_lineno=182,
__zend_orig_filename=0xee1888 "/home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c", __zend_orig_lineno=437) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2064
#2 0x00000000008cebf7 in _efree (ptr=0x2584910, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c", __zend_lineno=182,
__zend_orig_filename=0xee1888 "/home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c", __zend_orig_lineno=437) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2436
#3 0x00000000008eda0a in _zval_ptr_dtor (zval_ptr=0x25849a0, __zend_filename=0xee3d40 "/home/htf/workspace/php-5.4.27/Zend/zend_variables.c", __zend_lineno=182)
at /home/htf/workspace/php-5.4.27/Zend/zend_execute_API.c:437
#4 0x00000000008fe687 in _zval_ptr_dtor_wrapper (zval_ptr=0x25849a0) at /home/htf/workspace/php-5.4.27/Zend/zend_variables.c:182
#5 0x000000000091259f in zend_hash_destroy (ht=0x7f7263f6e380) at /home/htf/workspace/php-5.4.27/Zend/zend_hash.c:560
#6 0x00000000008fe2c5 in _zval_dtor_func (zvalue=0x7f726426fe50, __zend_filename=0xeea290 "/home/htf/workspace/php-5.4.27/Zend/zend_execute.c", __zend_lineno=901)
at /home/htf/workspace/php-5.4.27/Zend/zend_variables.c:45
#7 0x0000000000936656 in _zval_dtor (zvalue=0x7f726426fe50, __zend_filename=0xeea290 "/home/htf/workspace/php-5.4.27/Zend/zend_execute.c", __zend_lineno=901)
at /home/htf/workspace/php-5.4.27/Zend/zend_variables.h:35
#8 0x0000000000939747 in zend_assign_to_variable (variable_ptr_ptr=0x7f7263f8e738, value=0x7f726426f6a8) at /home/htf/workspace/php-5.4.27/Zend/zend_execute.c:901
#9 0x0000000000997ee5 in ZEND_ASSIGN_SPEC_CV_VAR_HANDLER (execute_data=0x7f726d04b2a8) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:33168
#10 0x000000000093b5fd in execute (op_array=0x21d58b0) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410
#11 0x0000000000901692 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/htf/workspace/php-5.4.27/Zend/zend.c:1315
#12 0x000000000087926a in php_execute_script (primary_file=0x7ffffe0038d0) at /home/htf/workspace/php-5.4.27/main/main.c:2502
#13 0x00000000009a32e3 in do_cli (argc=2, argv=0x7ffffe004d18) at /home/htf/workspace/php-5.4.27/sapi/cli/php_cli.c:989
#14 0x00000000009a4491 in main (argc=2, argv=0x7ffffe004d18) at /home/htf/workspace/php-5.4.27/sapi/cli/php_cli.c:1365

执行gdb后,死循环的进程会变成T的状态,表示正在Trace。这个是独占的,所以不能再使用strace/gdb或者其他ptrace工具对此进程进行调试。另外此进程会中断执行。gdb输入c后,程序继续向下运行。然后再次按下ctrl + c中断程序。 通过bt命令查看进程的调用栈。

代码如下:


(gdb) bt
#0 _zend_mm_alloc_int (heap=0x1eaa2c0, size=72, __zend_filename=0xe43410 "/home/htf/workspace/php-5.4.27/ext/standard/array.c", __zend_lineno=2719,
__zend_orig_filename=0xee5a38 "/home/htf/workspace/php-5.4.27/Zend/zend_hash.c", __zend_orig_lineno=412) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:1895
#1 0x00000000008ceb86 in _emalloc (size=72, __zend_filename=0xe43410 "/home/htf/workspace/php-5.4.27/ext/standard/array.c", __zend_lineno=2719,
__zend_orig_filename=0xee5a38 "/home/htf/workspace/php-5.4.27/Zend/zend_hash.c", __zend_orig_lineno=412) at /home/htf/workspace/php-5.4.27/Zend/zend_alloc.c:2425
#2 0x0000000000911d85 in _zend_hash_index_update_or_next_insert (ht=0x2257a10, h=3972, pData=0x7ffffe0012b0, nDataSize=8, pDest=0x0, flag=1,
__zend_filename=0xe43410 "/home/htf/workspace/php-5.4.27/ext/standard/array.c", __zend_lineno=2719) at /home/htf/workspace/php-5.4.27/Zend/zend_hash.c:412
#3 0x00000000007767e1 in zif_array_flip (ht=1, return_value=0x7f726424ea68, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1)
at /home/htf/workspace/php-5.4.27/ext/standard/array.c:2719
#4 0x000000000093c03e in zend_do_fcall_common_helper_SPEC (execute_data=0x7f726d04b2a8) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:643
#5 0x00000000009400e6 in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0x7f726d04b2a8) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:2233
#6 0x000000000093b5fd in execute (op_array=0x21d58b0) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410

两次的BT信息不一样,这是因为程序在不同的位置中断。看到execute (oparray=0x21d58b0) 这一行,这里就是PHP执行oparray的入口了。gdb下输入f 6,(通过调用栈编号可得)。

代码如下:


(gdb) f 6
#6 0x000000000093b5fd in execute (op_array=0x21d58b0) at /home/htf/workspace/php-5.4.27/Zend/zend_vm_execute.h:410
410 if ((ret = OPLINE->handler(execute_data TSRMLS_CC)) > 0) {
(gdb) p *op_array
$2 = {type = 2 '\002', function_name = 0x7f726d086540 "test", scope = 0x0, fn_flags = 134217728, prototype = 0x0, num_args = 2, required_num_args = 2, arg_info = 0x7f726d086bd8,
refcount = 0x7f726d0870f0, opcodes = 0x7f726424d600, last = 8, vars = 0x7f726424e890, last_var = 2, T = 1, brk_cont_array = 0x0, last_brk_cont = 0, try_catch_array = 0x0,
last_try_catch = 0, static_variables = 0x0, this_var = 4294967295, filename = 0x7f726424ba38 "/home/htf/wwwroot/include.php", line_start = 12, line_end = 15, doc_comment = 0x0,
doc_comment_len = 0, early_binding = 4294967295, literals = 0x7f726424eae0, last_literal = 4, run_time_cache = 0x7f726450bfb0, last_cache_slot = 1, reserved = {0x0, 0x0, 0x0, 0x0}}

这里的filename就能看到op_array是哪个PHP文件的。然后输入f 0进入当前位置。

代码如下:


(gdb) p **executor_globals.opline_ptr
$4 = {handler = 0x93ff9c , op1 = {constant = 1680133296, var = 1680133296, num = 1680133296, hash = 140129283132592, opline_num = 1680133296,
jmp_addr = 0x7f726424ccb0, zv = 0x7f726424ccb0, literal = 0x7f726424ccb0, ptr = 0x7f726424ccb0}, op2 = {constant = 0, var = 0, num = 0, hash = 0, opline_num = 0, jmp_addr = 0x0,
zv = 0x0, literal = 0x0, ptr = 0x0}, result = {constant = 32, var = 32, num = 32, hash = 32, opline_num = 32, jmp_addr = 0x20, zv = 0x20, literal = 0x20, ptr = 0x20},
extended_value = 1, lineno = 5, opcode = 60 '

这里的lineno表示OPCODE所在的代码行数,可以到对应文件里去看下是哪行代码。使用GDB可以查看到更多的信息,这里就不再一一介绍了,有兴趣各位可以自行尝试。

zbacktrace的使用

zend官方提供了一个gdb的脚本,对指令进行了封装,可以直接看到php函数的调用关系。在php源代码包的根目录中有一个.gdbinit。使用

代码如下:


source your_php_src_path/.gdbinit
zbacktrace

可以直接看到PHP函数的调用堆栈。

以上就是本文的全部内容了,希望大家能够喜欢。

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
4 Il y a quelques semaines By DDD
Musée à deux points: toutes les expositions et où les trouver
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Techniques de configuration courantes pour le débogage du noyau Linux à l'aide de GDB Techniques de configuration courantes pour le débogage du noyau Linux à l'aide de GDB Jul 05, 2023 pm 01:54 PM

Techniques de configuration courantes pour utiliser GDB pour déboguer le noyau Linux Introduction : Dans le développement Linux, utiliser GDB pour déboguer le noyau est une compétence très importante. GDB est un puissant outil de débogage qui peut aider les développeurs à localiser et à résoudre rapidement les bogues du noyau. Cet article présentera quelques techniques de configuration GDB courantes et comment utiliser GDB pour déboguer le noyau Linux. 1. Configurer l'environnement GDB Tout d'abord, nous devons configurer l'environnement GDB sur le système Linux. Veuillez vous assurer que l'outil GDB est installé sur votre système.

Méthodes de configuration courantes pour utiliser GDB pour déboguer les programmes ARM intégrés sous Linux Méthodes de configuration courantes pour utiliser GDB pour déboguer les programmes ARM intégrés sous Linux Jul 05, 2023 am 08:10 AM

Méthodes de configuration courantes pour utiliser GDB pour déboguer les programmes ARM intégrés sous Linux En tant que système informatique spécial, les systèmes embarqués sont généralement intégrés dans des appareils électroniques et utilisés pour contrôler et gérer les ressources matérielles. Afin de déboguer et d'analyser le fonctionnement des systèmes embarqués, nous devons utiliser des outils spécialisés. Parmi eux, GDB est un débogueur open source couramment utilisé qui peut s'exécuter sur des systèmes embarqués et communiquer avec des programmes. Cet article présentera les méthodes de configuration courantes pour utiliser GDB pour déboguer les programmes ARM intégrés sous Linux et donnera des exemples de code.

Comment déboguer les fonctions Golang à l'aide de GDB ? Comment déboguer les fonctions Golang à l'aide de GDB ? Apr 18, 2024 am 08:00 AM

Les étapes pour utiliser GDB pour déboguer les fonctions Go sont les suivantes : Installez le package de débogage GDB et Go. Compilez le programme avec les informations de débogage activées. Utilisez GDB pour lancer le programme. Définissez des points d'arrêt. Utilisez la commande run pour démarrer le programme. Utilisez les commandes de débogage pour déboguer.

Méthodes de configuration courantes pour utiliser GDB pour déboguer des programmes multithread sous Linux Méthodes de configuration courantes pour utiliser GDB pour déboguer des programmes multithread sous Linux Jul 04, 2023 pm 02:49 PM

Méthodes de configuration courantes pour utiliser GDB pour déboguer des programmes multithread sous Linux Introduction : En programmation multithread, le débogage est une tâche essentielle. GDB est un puissant débogueur qui peut nous aider à localiser et à résoudre les erreurs dans les programmes multithread. Cet article présentera les méthodes de configuration courantes pour utiliser GDB pour déboguer des programmes multithread sous Linux et fournira des exemples de code, dans l'espoir d'aider les lecteurs à mieux comprendre et utiliser GDB. 1. Installez GDB Tout d'abord, nous devons installer GDB sur le système Linux. Entrez dans le terminal

Comment résoudre le problème de la boucle infinie dans le développement C++ Comment résoudre le problème de la boucle infinie dans le développement C++ Aug 22, 2023 am 08:53 AM

Comment résoudre le problème de la boucle infinie dans le développement C++, la boucle infinie est un problème très courant mais très difficile. Lorsqu'un programme tombe dans une boucle infinie, cela empêchera le programme de s'exécuter normalement et peut même provoquer un crash du système. Par conséquent, résoudre des problèmes de boucle infinie est l’une des compétences essentielles du développement C++. Cet article présentera quelques méthodes courantes pour résoudre le problème de la boucle infinie. Vérification des conditions de boucle L'une des causes les plus courantes de boucles sans fin est des conditions de boucle incorrectes. Lorsque la condition de boucle est toujours vraie, la boucle continuera à s'exécuter, ce qui entraînera une boucle infinie.

Outils et techniques de débogage courants pour les systèmes Linux Outils et techniques de débogage courants pour les systèmes Linux Feb 23, 2024 pm 02:40 PM

Dans les systèmes Linux, le débogage est une partie cruciale du processus de développement et de maintenance du programme. Afin d'aider les développeurs à déboguer plus efficacement, Linux fournit une variété d'outils et de technologies de débogage puissants. Cet article présentera brièvement certains outils et techniques de débogage Linux couramment utilisés pour aider les développeurs à mieux déboguer. 1. Outils de débogage 1.gdb Dans les systèmes Linux, gdb est largement utilisé comme l'un des outils de débogage. Il aide les développeurs à suivre la cause des plantages du programme et fournit une série de commandes pour vérifier l'état du programme, modifier les variables et exécuter le code. . Pour démarrer le débogage, vous pouvez utiliser la commande suivante. $gdb./program où `./program` représente le fichier exécutable à déboguer. Une fois que gdb démarre,

Comment résoudre : erreur d'algorithme Java : boucle infinie Comment résoudre : erreur d'algorithme Java : boucle infinie Aug 25, 2023 pm 10:12 PM

Comment résoudre : Erreur d'algorithme Java : boucle infinie Introduction : Lors du processus d'écriture de programmes Java, nous rencontrons souvent diverses erreurs et exceptions. Parmi eux, la boucle infinie est un problème courant, qui fera tomber le programme dans un état de boucle infinie, empêchant le programme de s'exécuter normalement. Dans cet article, nous verrons comment résoudre le problème de la boucle infinie dans les algorithmes Java et fournirons des exemples de code. 1. La définition et la cause d'une boucle infinie : Une boucle infinie fait référence à une structure de boucle dans un programme qui n'a aucune condition de terminaison normale, provoquant l'exécution du programme dans une boucle infinie au sein de cette boucle.

Problèmes de boucle infinie rencontrés dans le développement du langage Go et leurs solutions Problèmes de boucle infinie rencontrés dans le développement du langage Go et leurs solutions Jul 01, 2023 pm 02:57 PM

Le langage Go est un langage de programmation open source de plus en plus privilégié par les développeurs pour ses performances de concurrence efficaces et ses capacités de gestion de mémoire intégrées. Cependant, dans le développement du langage Go, nous rencontrons parfois des problèmes de boucle infinie, ce qui donne beaucoup de maux de tête aux développeurs. Cet article abordera les problèmes de boucle infinie rencontrés dans le développement du langage Go et proposera quelques solutions. 1. Qu'est-ce qu'une boucle infinie ? Une boucle infinie fait référence à une situation dans laquelle une section de code dans un programme est exécutée de manière répétée un nombre infini de fois, empêchant le programme de continuer à s'exécuter. Habituellement, les boucles infinies sont causées par des erreurs de logique de code ou par un manque de

See all articles