Heim > Backend-Entwicklung > PHP-Tutorial > So führen Sie ein Speicher-Debugging in PHP durch

So führen Sie ein Speicher-Debugging in PHP durch

coldplay.xixi
Freigeben: 2023-04-09 11:52:02
nach vorne
2646 Leute haben es durchsucht

So führen Sie ein Speicher-Debugging in PHP durch

Speicher-Debugging

Dieses Kapitel ist eine kurze Einführung in das Speicher-Debugging von PHP-Quellcode. Dies ist kein vollständiger Kurs: Das Debuggen von Speicher ist nicht schwierig, aber Sie benötigen etwas Erfahrung in der Anwendung, und Sie werden wahrscheinlich viel Übung benötigen, wenn Sie in C geschriebenen Code entwerfen. Wir stellen hier einen sehr bekannten Speicher-Debugger vor: valgrind und wie man ihn mit PHP zum Debuggen von Speicherproblemen verwendet.

Verwandte Lernempfehlungen: PHP-Programmierung vom Einstieg bis zur Kompetenz

Einführung in Valgrind

Valgrind wird in vielen Unix-Umgebungen verwendet Bekanntes Tool zum Debuggen vieler häufiger Speicherprobleme in jeder in C/C++ geschriebenen Software. Valgrind ist ein vielseitiges Front-End-Tool für das Speicher-Debugging. Das am häufigsten verwendete Low-Level-Tool heißt „memcheck“. Die Funktionsweise besteht darin, die Heap-Zuweisung jeder Libc durch ihre eigene Heap-Zuweisung zu ersetzen und zu verfolgen, was Sie damit machen. Sie könnten auch an „massif“ interessiert sein: Es handelt sich um einen Speicher-Tracker, der nützlich ist, um die allgemeine Heap-Speichernutzung eines Programms zu verstehen.

Hinweis

Sie sollten die Valgrind-Dokumentation lesen, um mehr zu erfahren. Es ist gut geschrieben und enthält einige großartige Beispiele.

Um den Speicherzuordnungsaustausch durchzuführen, müssen Sie das Programm, das Sie analysieren möchten (in diesem Fall PHP), über valgrind ausführen, d. h. die Valgrind-Binärdatei starten.

Wenn Valgrind alle Heap-Zuweisungen von libc ersetzt und verfolgt, wird der Debugger tendenziell erheblich verlangsamt. Bei PHP werden Sie es bemerken. Obwohl die PHP-Verlangsamung nicht so drastisch ist, ist sie dennoch deutlich spürbar. Wenn Sie sie bemerken, machen Sie sich keine Sorgen, das ist normal.

Valgrind ist nicht das einzige Werkzeug, das Sie verwenden könnten, aber es ist das am häufigsten verwendete. Es gibt andere Tools wie Dr.Memory, LeakSanitizer, Electric Fence, AddressSanitizer.

Bevor Sie beginnen

Hier sind die Schritte, die erforderlich sind, um gute Erfahrungen mit dem Speicher-Debugging zu machen, die Wahrscheinlichkeit zu verringern, Fehler zu finden und die Debugging-Zeit zu verkürzen:

– Sie sollten immer verwenden Debug-Version von PHP. Der Versuch, Speicher in Produktions-Builds zu debuggen, ist irrelevant.
– Sie sollten den Debugger immer mit USE_ZEND_ALLOC = 0 starten. Wie Sie vielleicht im Kapitel „Zend Memory Manager“ erfahren haben, deaktiviert diese Umgebungsvariable ZendMM, wenn der aktuelle Prozess startet. Es wird dringend empfohlen, dies beim Starten des Speicherdebuggers zu tun. Es hilft, ZendMM vollständig zu umgehen, um die von Valgrind generierten Spuren zu verstehen.
– Es wird dringend empfohlen, den Speicherdebugger mit der Umgebung ZEND_DONT_UNLOAD_MODULES = 1 zu starten. Dadurch wird verhindert, dass PHP die .so-Datei der Erweiterung am Ende des Prozesses entlädt. Dies dient der besseren Verfolgung von Valgrind-Berichten. Wenn PHP die Erweiterung entlädt, wenn Valgrind seine Fehler anzeigt, ist sie später unvollständig, da die Datei, aus der die Informationen stammen, nicht mehr Teil des Prozessspeicherabbilds ist.
– Möglicherweise benötigen Sie etwas Unterdrückung. Wenn Sie PHP am Ende des Prozesses anweisen, seine Erweiterung nicht zu entladen, erhalten Sie möglicherweise falsch positive Ergebnisse in der Valgrind-Ausgabe. PHP-Erweiterungen werden auf Lecks überprüft. Wenn Sie auf Ihrer Plattform Fehlalarme erhalten, können Sie diese mithilfe der Unterdrückung auf diese Weise deaktivieren. Fühlen Sie sich frei, anhand solcher Beispiele Ihr eigenes zu schreiben.
– Im Vergleich zu Zend Memory Manager ist Valgrind eindeutig ein besseres Tool zum Auffinden von Lecks und anderen speicherbezogenen Problemen. Sie sollten valgrind immer für Ihren Code ausführen. Dies ist ein Schritt, den praktisch jeder C-Programmierer ausführen muss. Egal, ob es daran liegt, dass es abstürzt und Sie es finden und debuggen möchten, oder ob Sie es als hochwertiges Tool ausführen, das scheinbar keinen Schaden anrichten kann: Valgrind ist das Tool, das versteckte Fehler aufzeigt und bereit ist, diese zu beseitigen einmal oder später weg. Verwenden Sie es auch dann, wenn Sie der Meinung sind, dass mit Ihrem Code alles in Ordnung zu sein scheint: Sie könnten überrascht sein.

Warnung

Sie müssen valgrind (oder einen beliebigen Speicher-Debugger) in Ihrem Programm verwenden. Wie bei jedem leistungsstarken C-Programm ist es unmöglich, 100 % sicher zu sein, ohne den Speicher zu debuggen. Speicherfehler können schädliche Sicherheitsprobleme verursachen und Programmabstürze hängen oft von vielen, oft zufälligen Parametern ab.

Beispiel zur Erkennung von Speicherlecks

Erste Schritte

Valgrind ist ein vollständiger Heap-Speicher-Debugger. Es kann auch prozedurale Speicherzuordnungen und Funktionsstapel debuggen. Weitere Informationen finden Sie in der Dokumentation.

Lassen Sie uns dynamische Speicherlecks erkennen und ein einfaches, häufigstes Leck ausprobieren:

PHP_RINIT_FUNCTION(pib)
{
    void *foo = emalloc(128);
}
Nach dem Login kopieren

Der obige Code verliert 128 Bytes pro Anfrage, da er keine efree() zugehörigen Aufrufe im Zusammenhang mit einem solchen Puffer hat. Da es sich um einen Aufruf von emalloc() handelt, durchläuft er den Zend Memory Manager, sodass wir später darüber gewarnt werden, wie wir im ZendMM-Kapitel gesehen haben. Wir möchten auch sehen, ob Valgrind das Leck bemerken kann:

> ZEND_DONT_UNLOAD_MODULES=1 USE_ZEND_ALLOC=0 valgrind --leak-check=full --suppressions=/path/to/suppression
--show-reachable=yes --track-origins=yes ~/myphp/bin/php -dextension=pib.so /tmp/foo.php
Nach dem Login kopieren

Wir verwenden Valgrind, um den PHP-CLI-Prozess zu starten. Wir gehen hier von einer Erweiterung namens „pib“ aus. Hier ist die Ausgabe:

==28104== 128 bytes in 1 blocks are definitely lost in loss record 1 of 1
==28104==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28104==    by 0xA3701E: __zend_malloc (zend_alloc.c:2820)
==28104==    by 0xA362E7: _emalloc (zend_alloc.c:2413)
==28104==    by 0xE896F99: zm_activate_pib (pib.c:1880)
==28104==    by 0xA79F1B: zend_activate_modules (zend_API.c:2537)
==28104==    by 0x9D31D3: php_request_startup (main.c:1673)
==28104==    by 0xB5909A: do_cli (php_cli.c:964)
==28104==    by 0xB5A423: main (php_cli.c:1381)

==28104== LEAK SUMMARY:
==28104==    definitely lost: 128 bytes in 1 blocks
==28104==    indirectly lost: 0 bytes in 0 blocks
==28104==    possibly lost: 0 bytes in 0 blocks
==28104==    still reachable: 0 bytes in 0 blocks
==28104==    suppressed: 7,883 bytes in 40 blocks
Nach dem Login kopieren

Unserer Meinung nach müssen wir uns auf „absolut verloren“ konzentrieren.

Hinweis

Details zu den verschiedenen von memcheck ausgegebenen Feldern finden Sie hier.

Hinweis

Wir verwenden USE_ZEND_ALLOC = 0, um Zend Memory Manager zu deaktivieren und vollständig zu umgehen. Jeder Aufruf seiner API (z. B. emalloc()) führt direkt zu einem libc-Aufruf, wie wir im Calgrind-Ausgabestapelrahmen sehen können.

Valgrind hat unsere Verletzlichkeit erkannt.

Einfach, jetzt können wir die persistente Zuweisung verwenden (d. h. ZendMM umgehen und die dynamische Speicherzuweisung der herkömmlichen libc verwenden), um Lecks zu erzeugen. Los:

PHP_RINIT_FUNCTION(pib)
{
    void *foo = malloc(128);
}
Nach dem Login kopieren

Hier ist der Bericht:

==28758==    128 bytes in 1 blocks are definitely lost in loss record 1 of 1
==28758==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28758==    by 0xE896F82: zm_activate_pib (pib.c:1880)
==28758==    by 0xA79F1B: zend_activate_modules (zend_API.c:2537)
==28758==    by 0x9D31D3: php_request_startup (main.c:1673)
==28758==    by 0xB5909A: do_cli (php_cli.c:964)
==28758==    by 0xB5A423: main (php_cli.c:1381)
Nach dem Login kopieren

Auch erwischt.

Hinweis

Valgrind fängt wirklich alles ein. Jedes kleine vergessene Byte irgendwo in der riesigen Prozessspeicherkarte wird von Valgrinds Augen gemeldet. Du kannst nicht bestehen.

Komplexere Anwendungsfälle

Dies ist ein komplexeres Setup. Können Sie das Leck im folgenden Code erkennen?

static zend_array ar;

PHP_MINIT_FUNCTION(pib)
{
    zend_string *str;
    zval string;

    str = zend_string_init("yo", strlen("yo"), 1);
    ZVAL_STR(&string, str);

    zend_hash_init(&ar, 8, NULL, ZVAL_PTR_DTOR, 1);
    zend_hash_next_index_insert(&ar, &string);
}
Nach dem Login kopieren

Zwei Leaks hier. Zuerst weisen wir einen zend_string zu, geben ihn aber nicht frei. Zweitens weisen wir einen neuen zend_hash zu, geben ihn aber auch nicht frei. Beginnen wir mit Valgrind und schauen wir uns die Ergebnisse an:

==31316== 296 (264 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 1 of 2
==32006==    by 0xA3701E: __zend_malloc (zend_alloc.c:2820)
==32006==    by 0xA814B2: zend_hash_real_init_ex (zend_hash.c:133)
==32006==    by 0xA816D2: zend_hash_check_init (zend_hash.c:161)
==32006==    by 0xA83552: _zend_hash_index_add_or_update_i (zend_hash.c:714)
==32006==    by 0xA83D58: _zend_hash_next_index_insert (zend_hash.c:841)
==32006==    by 0xE896AF4: zm_startup_pib (pib.c:1781)
==32006==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==32006==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==32006==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==32006==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)

==31316== 32 bytes in 1 blocks are indirectly lost in loss record 2 of 2
==31316==    by 0xA3701E: __zend_malloc (zend_alloc.c:2820)
==31316==    by 0xE880B0D: zend_string_alloc (zend_string.h:122)
==31316==    by 0xE880B76: zend_string_init (zend_string.h:158)
==31316==    by 0xE896F9D: zm_activate_pib (pib.c:1781)
==31316==    by 0xA79F1B: zend_activate_modules (zend_API.c:2537)
==31316==    by 0x9D31D3: php_request_startup (main.c:1673)
==31316==    by 0xB5909A: do_cli (php_cli.c:964)
==31316==    by 0xB5A423: main (php_cli.c:1381)

==31316== LEAK SUMMARY:
==31316== definitely lost: 328 bytes in 2 blocks
Nach dem Login kopieren

Wie erwartet werden beide Leaks gemeldet. Wie Sie sehen, ist Valgrind präzise und bringt Ihr Auge dorthin, wo es sein soll.

Beheben Sie sie jetzt:

PHP_MSHUTDOWN_FUNCTION(pib)
{
    zend_hash_destroy(&ar);
}
Nach dem Login kopieren

Wir haben persistente Arrays in MSHUTDOWN am Ende des PHP-Programms zerstört. Wenn wir es erstellen, übergeben wir es als Destruktor an ZVAL_PTR_DTOR und es führt diesen Rückruf für alle eingefügten Elemente aus. Dies ist der Destruktor von zval, der zval beim Parsen seines Inhalts zerstört. Für den Typ IS_STRING gibt der Destruktor den Typ zend_string frei und gibt ihn bei Bedarf frei. Fertig

Hinweis

Wie Sie sehen können, ist PHP – wie jedes C-starke Programm – voller verschachtelter Zeiger. zend_string ist in zval gekapselt und selbst Teil von zend_array. Ein Array-Leck führt offensichtlich dazu, dass zval und zend_string verloren gehen, aber zvals wird nicht auf dem Heap zugewiesen (wir weisen auf dem Stapel zu), sodass keine Lecks gemeldet werden. Sie sollten sich daran gewöhnen, dass das Vergessen, zusammengesetzte Strukturen wie zend_array freizugeben/freizugeben, zu vielen Lecks führen kann, da Strukturen oft verschachtelte Strukturen, verschachtelte Strukturen usw. haben.

Pufferüberlauf-/-unterlauferkennung

Speicherlecks sind schlimm. Dies führt dazu, dass Ihr Programm einmal oder später OOM auslöst und den Host erheblich verlangsamt, da dieser mit der Zeit immer weniger freien Speicher erhält. Dies ist ein Zeichen für einen Speicherverlust.

Aber noch schlimmer: Pufferzugriff außerhalb der Grenzen. Der Zugriff auf Zeiger außerhalb der Zuweisungsgrenzen ist die Wurzel vieler bösartiger Vorgänge (z. B. das Erstellen einer Root-Shell auf Ihrem Computer), daher sollten Sie sie auf jeden Fall verhindern. Kleinere Zugriffe außerhalb des zulässigen Bereichs können aufgrund von Speicherbeschädigung häufig auch zu Programmabstürzen führen. Es hängt jedoch alles von der Hardware-Zielmaschine, dem verwendeten Compiler und den verwendeten Optionen, dem Speicherlayout des Betriebssystems, der verwendeten Libc usw. ab ... vielen Faktoren.

Zugriffe außerhalb der Grenzen sind also sehr ärgerlich, es sind Bomben, die explodieren können oder auch nicht, entweder in einer Minute, oder wenn Sie sehr viel Glück haben, dauern sie ewig. Sie explodieren nicht.

  • Valgrind* ist ein Speicher-Debugger und daher in der Lage, jeden Out-of-Bounds-Zugriff aus jedem Speicherbereich (Heap und Stack) zu erkennen. Dies ist das gleiche Memcheck-Tool, das zum Auffinden von Lecks verwendet wird.

Sehen wir uns ein einfaches Beispiel an:

PHP_MINIT_FUNCTION(pib)
{
    char *foo = malloc(16);
    foo[16] = 'a';
    foo[-1] = 'a';
}
Nach dem Login kopieren

Dieser Code weist einen Puffer zu und schreibt Daten absichtlich ein Byte nach der Grenze und ein Byte nach der Grenze. Wenn Sie nun Code wie diesen ausführen, ist die Wahrscheinlichkeit, dass es sofort und dann zufällig abstürzt, etwa eins zu zwei. Möglicherweise haben Sie auch eine Sicherheitslücke in PHP erstellt, die jedoch möglicherweise nicht aus der Ferne ausgenutzt werden kann (dieses Verhalten kommt selten vor).

Warnung

Zugriff außerhalb der Grenzen führt zu undefiniertem Verhalten. Es gibt keine Möglichkeit vorherzusagen, was passieren wird, aber stellen Sie sicher, dass es entweder schlimm (sofortiger Absturz) oder schrecklich (Sicherheitsproblem) ist. Erinnern.

Lassen Sie uns Valgrind bitten, es mit der exakt gleichen Befehlszeile wie zuvor zu starten. Außer der Ausgabe hat sich nichts geändert:

==12802== Invalid write of size 1
==12802==    at 0xE896A98: zm_startup_pib (pib.c:1772)
==12802==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==12802==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==12802==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==12802==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==12802==    by 0x9D4541: php_module_startup (main.c:2260)
==12802==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==12802==    by 0xB5A367: main (php_cli.c:1348)
==12802==  Address 0xeb488f0 is 0 bytes after a block of size 16 alloc'd
==12802==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12802==    by 0xE896A85: zm_startup_pib (pib.c:1771)
==12802==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==12802==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==12802==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==12802==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==12802==    by 0x9D4541: php_module_startup (main.c:2260)
==12802==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==12802==    by 0xB5A367: main (php_cli.c:1348)
==12802==
==12802== Invalid write of size 1
==12802==    at 0xE896AA6: zm_startup_pib (pib.c:1773)
==12802==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==12802==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==12802==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==12802==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==12802==    by 0x9D4541: php_module_startup (main.c:2260)
==12802==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==12802==    by 0xB5A367: main (php_cli.c:1348)
==12802==  Address 0xeb488df is 1 bytes before a block of size 16 alloc'd
==12802==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12802==    by 0xE896A85: zm_startup_pib (pib.c:1771)
==12802==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==12802==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==12802==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==12802==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==12802==    by 0x9D4541: php_module_startup (main.c:2260)
==12802==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==12802==    by 0xB5A367: main (php_cli.c:1348)
Nach dem Login kopieren

Diese beiden ungültigen Schreibvorgänge wurden erkannt, jetzt ist Ihr Ziel um sie aufzuspüren und zu reparieren.

在这里,我们使用了一个示例,其中我们超出范围地写入内存,这是最糟糕的情况,因为您的写入操作成功后(可能会立即导致SIGSEGV)将覆盖该指针旁边的一些关键区域。当我们使用libc的malloc()进行分配时,我们将覆盖libc用于管理和跟踪其分配的关键头尾块。取决于许多因素(平台,使用的libc,如何编译等等),这将导致崩溃。

Valgrind也可能报告无效读取。这意味着您将在分配的指针的范围之外执行内存读取操作。更好的情况是块被覆盖,但您仍然不应该访问内存区域,在这种情况下又可能会导致立即崩溃,或者稍后崩溃,或者永远不会访问?不要那样做

Note

一旦您在valgrind的输出中读取“ Invalid”,那对您来说真的很不好。无论是无效的读取还是写入,您的代码中都存在问题,因此您应该将这个问题视为高风险:现在就真正修复它。

这是有关字符串连接的第二个示例:

char *foo = strdup("foo");
char *bar = strdup("bar");

char *foobar = malloc(strlen("foo") + strlen("bar"));

memcpy(foobar, foo, strlen(foo));
memcpy(foobar + strlen("foo"), bar, strlen(bar));

fprintf(stderr, "%s", foobar);

free(foo);
free(bar);
free(foobar);
Nach dem Login kopieren

你能发现问题吗?

让我们问一下valgrind:

==13935== Invalid read of size 1
==13935==    at 0x4C30F74: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13935==    by 0x768203E: fputs (iofputs.c:33)
==13935==    by 0xE896B91: zm_startup_pib (pib.c:1779)
==13935==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==13935==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==13935==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==13935==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==13935==    by 0x9D4541: php_module_startup (main.c:2260)
==13935==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==13935==    by 0xB5A367: main (php_cli.c:1348)
==13935==  Address 0xeb48986 is 0 bytes after a block of size 6 alloc'd
==13935==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13935==    by 0xE896B14: zm_startup_pib (pib.c:1774)
==13935==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==13935==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==13935==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==13935==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==13935==    by 0x9D4541: php_module_startup (main.c:2260)
==13935==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==13935==    by 0xB5A367: main (php_cli.c:1348)
Nach dem Login kopieren

第1779行指向fprintf()调用。该调用确实要求fputs(),其本身称为strlen()(均来自libc),在这里strlen()读取1个字节无效。

我们只是忘记了\ 0来终止我们的字符串。我们传递fprintf()无效的字符串。它首先尝试计算调用strlen()的字符串的长度。然后strlen()将扫描缓冲区,直到找到\ 0,并且它将扫描缓冲区的边界,因为我们忘记了对其进行零终止。我们在这里很幸运,strlen()仅从末尾传递一个字节。那可能更多,并且可能崩溃了,因为我们真的不知道下一个\ 0在内存中的位置,这是随机的。

解:

size_t len   = strlen("foo") + strlen("bar") + 1;   /* note the +1 for \0 */
char *foobar = malloc(len);

/* ... ... same code ... ... */

foobar[len - 1] = '\0'; /* terminate the string properly */
Nach dem Login kopieren

Note

上述错误是C语言中最常见的错误之一。它们被称为一次性错误:您忘记仅分配一个字节,但是由于以下原因,您将在代码中产生大量问题那。

最后,这里是最后一个示例,展示了一个有余使用的场景。这也是C编程中的一个非常常见的错误,与错误的内存访问一样严重:它创建了安全缺陷,可能导致非常讨厌的行为。显然,valgrind可以检测到无用后使用。这是一个:

char *foo = strdup("foo");
free(foo);

memcpy(foo, "foo", sizeof("foo"));
Nach dem Login kopieren

同样,这里是一个与PHP无关的PHP场景。我们释放一个指针,然后再使用它。这是一个大错误。让我们问一下valgrind:

==14594== Invalid write of size 1
==14594==    at 0x4C3245C: memcpy@GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14594==    by 0xE896AA1: zm_startup_pib (pib.c:1774)
==14594==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==14594==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==14594==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==14594==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==14594==    by 0x9D4541: php_module_startup (main.c:2260)
==14594==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==14594==    by 0xB5A367: main (php_cli.c:1348)
==14594==  Address 0xeb488e0 is 0 bytes inside a block of size 4 free'd
==14594==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14594==    by 0xE896A86: zm_startup_pib (pib.c:1772)
==14594==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==14594==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==14594==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==14594==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==14594==    by 0x9D4541: php_module_startup (main.c:2260)
==14594==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==14594==    by 0xB5A367: main (php_cli.c:1348)
==14594==  Block was alloc'd at
==14594==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14594==    by 0x769E8D9: strdup (strdup.c:42)
==14594==    by 0xE896A70: zm_startup_pib (pib.c:1771)
==14594==    by 0xA774F7: zend_startup_module_ex (zend_API.c:1843)
==14594==    by 0xA77559: zend_startup_module_zval (zend_API.c:1858)
==14594==    by 0xA85AF5: zend_hash_apply (zend_hash.c:1508)
==14594==    by 0xA77B25: zend_startup_modules (zend_API.c:1969)
==14594==    by 0x9D4541: php_module_startup (main.c:2260)
==14594==    by 0xB5802F: php_cli_startup (php_cli.c:427)
==14594==    by 0xB5A367: main (php_cli.c:1348)
Nach dem Login kopieren

这里的一切再次变得清晰。

结论

在投入生产之前,请使用内存调试器。正如您在本章中学到的那样,您在计算中忘记的小字节可能导致可利用的安全漏洞。它还经常(非常频繁地)导致简单的崩溃。这意味着您的扩展很酷,可以减少整个服务器(服务器)及其每个客户端的数量。

C是一种非常严格的编程语言。您将获得数十亿字节的内存来进行编程,并且必须安排这些内存来执行一些计算。但是请不要搞砸这种强大的功能:在最好的情况下(罕见),什么都不会发生,在更坏的情况下(非常常见),您会在这里和那里随机崩溃,在最坏的情况下,您会创建一个漏洞在恰好可以被远程利用的程序中...

您的工具娴熟,聪明,请确实照顾机器内存。

Das obige ist der detaillierte Inhalt vonSo führen Sie ein Speicher-Debugging in PHP durch. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
php
Quelle:learnku.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage