您好,登錄后才能下訂單哦!
如何進(jìn)行php內(nèi)存調(diào)試?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
本章是有關(guān)PHP源代碼的內(nèi)存調(diào)試的簡(jiǎn)要介紹。 這不是一門完整的課程:內(nèi)存調(diào)試并不難, 但是你需要一些它的使用經(jīng)驗(yàn),大量的練習(xí)可能是你在設(shè)計(jì)任何C編寫的代碼時(shí)都必須要做的事情。我們將在這里介紹一個(gè)非常著名的內(nèi)存調(diào)試器: valgrind; 以及如何將其與PHP一起使用來調(diào)試內(nèi)存問題。
Valgrind是許多Unix環(huán)境下使用的知名工具,可以在任何C/C++編寫的軟件中調(diào)試許多常見的內(nèi)存問題。 Valgrind 是有關(guān)內(nèi)存調(diào)試的多功能前端工具。最常用的底層工具稱為 “memcheck”。它的工作方式是用自己的堆分配替換每個(gè)libc的堆分配,并跟蹤你對(duì)它們所做的事情。你可能還會(huì)對(duì) “massif” 感興趣: 它是一個(gè)內(nèi)存跟蹤器,對(duì)于了解程序的常規(guī)堆內(nèi)存使用情況非常有用。
注意
你應(yīng)該閱讀Valgrind文檔,以進(jìn)一步了解。 它寫得很好,帶有一些典型的例子。
為了進(jìn)行內(nèi)存分配替換,你需要通過 valgrind 運(yùn)行要分析的程序(此處為PHP),也就是啟動(dòng) valgrind 二進(jìn)制文件。
當(dāng) valgrind 替換并跟蹤所有 libc 的堆分配時(shí),它往往會(huì)大大降低調(diào)試程序的速度。對(duì)于PHP,你會(huì)注意到它。盡管 PHP 的速度下降并不那么劇烈,但是仍然可以清楚地感覺到;如果你注意到它,不用擔(dān)心,這是正常的。
Valgrind 不是你可能會(huì)使用的唯一工具,但是是最常用的工具。還有其他工具,例如 Dr.Memory、LeakSanitizer、Electric Fence、AddressSanitizer。
以下是在存儲(chǔ)器調(diào)試方面具有良好經(jīng)驗(yàn)并減輕發(fā)現(xiàn)缺陷并減少調(diào)試時(shí)間的機(jī)會(huì)所需的步驟:
-您應(yīng)始終使用PHP的調(diào)試版本。嘗試調(diào)試生產(chǎn)版本中的內(nèi)存是無關(guān)緊要的。
-您應(yīng)該始終在 USE_ZEND_ALLOC = 0 環(huán)境下啟動(dòng)調(diào)試器。您可能已經(jīng)在Zend Memory Manager章節(jié)中了解到,此環(huán)境var會(huì)在當(dāng)前進(jìn)程啟動(dòng)時(shí)禁用ZendMM。強(qiáng)烈建議在啟動(dòng)內(nèi)存調(diào)試器時(shí)這樣做。完全繞過ZendMM有助于了解valgrind生成的跟蹤。
-強(qiáng)烈建議在環(huán)境 ZEND_DONT_UNLOAD_MODULES = 1 下啟動(dòng)內(nèi)存調(diào)試器。這樣可以防止PHP在過程結(jié)束時(shí)卸載擴(kuò)展程序的.so文件。這是為了獲得更好的valgrind報(bào)告跟蹤;如果在valgrind將要顯示其錯(cuò)誤時(shí)PHP將卸載擴(kuò)展名,則稍后將不完整,因?yàn)閺闹蝎@取信息的文件不再是進(jìn)程內(nèi)存映像的一部分。
-您可能需要一些抑制措施。當(dāng)您告訴PHP在過程結(jié)束時(shí)不要卸載其擴(kuò)展名時(shí),可能會(huì)在valgrind輸出中給您誤報(bào)。將檢查PHP擴(kuò)展是否泄漏,如果您在平臺(tái)上誤報(bào),則可以使用抑制功能將其關(guān)閉像這樣??梢愿鶕?jù)這樣的示例隨意編寫自己的文件。
-與Zend Memory Manager相比,Valgrind顯然是更好的工具,可以查找泄漏和其他與內(nèi)存相關(guān)的問題。您應(yīng)該始終在代碼上運(yùn)行valgrind,這實(shí)際上是每個(gè)C程序員都必須執(zhí)行的步驟。無論是因?yàn)楸罎⒍胍业讲⒄{(diào)試它,還是作為看起來好像沒有任何壞處的高質(zhì)量工具來運(yùn)行它,valgrind都是這種工具,它可以指出隱藏的瑕疵,準(zhǔn)備好將其吹拂一次或以后。即使您認(rèn)為代碼似乎一切都很好,也可以使用它:您可能會(huì)感到驚訝。
Warning
您**必須在程序上使用valgrind(或任何內(nèi)存調(diào)試器)。對(duì)于每個(gè)強(qiáng)大的C程序,要不調(diào)試內(nèi)存就不可能100%充滿信心。內(nèi)存錯(cuò)誤會(huì)導(dǎo)致有害的安全問題,并且程序崩潰通常取決于許多參數(shù),通常是隨機(jī)的。
Valgrind是一個(gè)完整的堆內(nèi)存調(diào)試器。它還可以調(diào)試過程內(nèi)存映射和功能堆棧。請(qǐng)?jiān)谄湮臋n中獲取更多信息。
讓我們?nèi)z測(cè)動(dòng)態(tài)內(nèi)存泄漏,并嘗試一個(gè)簡(jiǎn)單的,最常見的泄漏:
PHP_RINIT_FUNCTION(pib) { void *foo = emalloc(128); }
上面的代碼每次請(qǐng)求都會(huì)泄漏128字節(jié),因?yàn)樗鼪]有與此類緩沖區(qū)有關(guān)的efree()
相關(guān)調(diào)用。由于它是對(duì)emalloc()
的調(diào)用,因此會(huì)通過Zend Memory Manager,因此稍后會(huì)警告我們就像我們?cè)赯endMM章節(jié)中看到的那樣。我們還要看看valgrind是否可以注意到泄漏:
> 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
我們使用valgrind啟動(dòng)PHP-CLI進(jìn)程。我們?cè)谶@里假設(shè)一個(gè)名為“ pib”的擴(kuò)展名。這是輸出:
==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
在我們看來,“絕對(duì)失落”是我們必須關(guān)注的。
Note
有關(guān)memcheck輸出的不同字段的詳細(xì)信息,請(qǐng)查看。
Note
我們使用
USE_ZEND_ALLOC = 0
禁用并完全繞過Zend Memory Manager。對(duì)其API的每次調(diào)用(例如emalloc()
)將直接導(dǎo)致libc調(diào)用,就像我們?cè)赾algrind輸出堆棧幀上可以看到的那樣。
Valgrind抓住了我們的漏洞。
很容易,現(xiàn)在我們可以使用持久分配(也就是繞過ZendMM并使用傳統(tǒng)libc的動(dòng)態(tài)內(nèi)存分配)來產(chǎn)生泄漏。走:
PHP_RINIT_FUNCTION(pib) { void *foo = malloc(128); }
這是報(bào)告:
==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)
也抓到了。
Note
Valgrind確實(shí)可以捕獲所有內(nèi)容。巨大的進(jìn)程內(nèi)存映射中某個(gè)地方的每一個(gè)被遺忘的小字節(jié)都會(huì)被valgrind的眼睛報(bào)告。您無法通過。
這是一個(gè)更復(fù)雜的設(shè)置。您可以在下面的代碼中發(fā)現(xiàn)泄漏嗎?
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); }
這里有兩個(gè)泄漏。首先,我們分配一個(gè)zend_string,但我們沒有釋放它。其次,我們分配一個(gè)新的zend_hash,但是我們也不釋放它。讓我們用valgrind啟動(dòng)它,然后查看結(jié)果:
==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
如預(yù)期的那樣,兩個(gè)泄漏都被報(bào)告。如您所見,valgrind是準(zhǔn)確的,它將您的眼睛放在需要的地方。
現(xiàn)在修復(fù)它們:
PHP_MSHUTDOWN_FUNCTION(pib) { zend_hash_destroy(&ar); }
我們?cè)赑HP程序結(jié)束時(shí)在MSHUTDOWN中銷毀了持久數(shù)組。創(chuàng)建它時(shí),我們將其作為析構(gòu)函數(shù)傳遞給ZVAL_PTR_DTOR
,它將在插入的所有項(xiàng)目上運(yùn)行該回調(diào)。這是zval的析構(gòu)函數(shù),它將破壞zval分析它們的內(nèi)容。對(duì)于IS_STRING
類型,析構(gòu)函數(shù)將釋放zend_string
并在必要時(shí)釋放它。做完了
Note
如您所見,PHP-像任何C語(yǔ)言強(qiáng)程序一樣-充滿了嵌套的指針。
zend_string
封裝在zval
中,其本身是zend_array
的一部分。泄漏數(shù)組顯然會(huì)泄漏zval
和zend_string
,但是zvals
沒有分配堆(我們?cè)诙褩I戏峙?,因此沒有泄漏報(bào)告。您應(yīng)該習(xí)慣這樣一個(gè)事實(shí),即忘記釋放/釋放諸如zend_array
之類的復(fù)合結(jié)構(gòu)會(huì)導(dǎo)致大量泄漏,因?yàn)榻Y(jié)構(gòu)經(jīng)常會(huì)嵌入結(jié)構(gòu),嵌入結(jié)構(gòu)等。
內(nèi)存泄漏很糟糕。這將導(dǎo)致您的程序一次或以后觸發(fā)OOM,并且將大大降低主機(jī)的速度,因?yàn)殡S著時(shí)間的流逝,后者將獲得越來越少的可用內(nèi)存。這是內(nèi)存泄漏的征兆。
但是更糟的是:緩沖區(qū)越界訪問。訪問超出分配限制的指針是許多邪惡操作(例如在計(jì)算機(jī)上獲得root shell)的根源,因此您絕對(duì)應(yīng)該防止它們。較輕的越界訪問也經(jīng)常會(huì)由于內(nèi)存損壞而導(dǎo)致程序崩潰。但是,這全部取決于硬件目標(biāo)計(jì)算機(jī),使用的編譯器和選項(xiàng),操作系統(tǒng)內(nèi)存布局,使用的libc等……許多因素。
因此,越界訪問非常令人討厭,它們是炸彈,可能會(huì)爆炸,也可能不會(huì)爆炸,或者在一分鐘內(nèi),或者如果您非常幸運(yùn),它們將永遠(yuǎn)不會(huì)爆炸。
讓我們看一個(gè)簡(jiǎn)單的例子:
PHP_MINIT_FUNCTION(pib) { char *foo = malloc(16); foo[16] = 'a'; foo[-1] = 'a'; }
這段代碼分配了一個(gè)緩沖區(qū),并故意在邊界后一個(gè)字節(jié)和邊界后一個(gè)字節(jié)寫入數(shù)據(jù)?,F(xiàn)在,如果您運(yùn)行這樣的代碼,您就有大約兩次機(jī)會(huì)中有一次立即崩潰,然后隨機(jī)崩潰。您可能還已經(jīng)在PHP中創(chuàng)建了一個(gè)安全漏洞,但是它可能無法被遠(yuǎn)程利用(這種行為很少見)。
Warning
越界訪問導(dǎo)致不確定的行為。無法預(yù)料會(huì)發(fā)生什么,但是請(qǐng)確保它不好(立即崩潰)或可怕(安全問題)。記得。
讓我們問一下valgrind,使用與之前完全相同的命令行來啟動(dòng)它,除了輸出內(nèi)容外,其他都沒有改變:
==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)
這兩個(gè)無效的寫入都已被檢測(cè)到,現(xiàn)在您的目標(biāo)是跟蹤并修復(fù)它們。
在這里,我們使用了一個(gè)示例,其中我們超出范圍地寫入內(nèi)存,這是最糟糕的情況,因?yàn)槟膶懭氩僮鞒晒?可能會(huì)立即導(dǎo)致SIGSEGV)將覆蓋該指針旁邊的一些關(guān)鍵區(qū)域。當(dāng)我們使用libc的malloc()
進(jìn)行分配時(shí),我們將覆蓋libc用于管理和跟蹤其分配的關(guān)鍵頭尾塊。取決于許多因素(平臺(tái),使用的libc,如何編譯等等),這將導(dǎo)致崩潰。
Valgrind也可能報(bào)告無效讀取。這意味著您將在分配的指針的范圍之外執(zhí)行內(nèi)存讀取操作。更好的情況是塊被覆蓋,但您仍然不應(yīng)該訪問內(nèi)存區(qū)域,在這種情況下又可能會(huì)導(dǎo)致立即崩潰,或者稍后崩潰,或者永遠(yuǎn)不會(huì)訪問?不要那樣做
Note
一旦您在valgrind的輸出中讀取“ Invalid”,那對(duì)您來說真的很不好。無論是無效的讀取還是寫入,您的代碼中都存在問題,因此您應(yīng)該將這個(gè)問題視為高風(fēng)險(xiǎn):現(xiàn)在就真正修復(fù)它。
這是有關(guān)字符串連接的第二個(gè)示例:
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);
你能發(fā)現(xiàn)問題嗎?
讓我們問一下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)
第1779行指向fprintf()
調(diào)用。該調(diào)用確實(shí)要求fputs()
,其本身稱為strlen()
(均來自libc),在這里strlen()
讀取1個(gè)字節(jié)無效。
我們只是忘記了\ 0
來終止我們的字符串。我們傳遞fprintf()
無效的字符串。它首先嘗試計(jì)算調(diào)用strlen()
的字符串的長(zhǎng)度。然后strlen()
將掃描緩沖區(qū),直到找到\ 0
,并且它將掃描緩沖區(qū)的邊界,因?yàn)槲覀兺浟藢?duì)其進(jìn)行零終止。我們?cè)谶@里很幸運(yùn),strlen()
僅從末尾傳遞一個(gè)字節(jié)。那可能更多,并且可能崩潰了,因?yàn)槲覀冋娴牟恢老乱粋€(gè)\ 0
在內(nèi)存中的位置,這是隨機(jī)的。
解:
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 */
Note
上述錯(cuò)誤是C語(yǔ)言中最常見的錯(cuò)誤之一。它們被稱為一次性錯(cuò)誤:您忘記僅分配一個(gè)字節(jié),但是由于以下原因,您將在代碼中產(chǎn)生大量問題那。
最后,這里是最后一個(gè)示例,展示了一個(gè)有余使用的場(chǎng)景。這也是C編程中的一個(gè)非常常見的錯(cuò)誤,與錯(cuò)誤的內(nèi)存訪問一樣嚴(yán)重:它創(chuàng)建了安全缺陷,可能導(dǎo)致非常討厭的行為。顯然,valgrind可以檢測(cè)到無用后使用。這是一個(gè):
char *foo = strdup("foo"); free(foo); memcpy(foo, "foo", sizeof("foo"));
同樣,這里是一個(gè)與PHP無關(guān)的PHP場(chǎng)景。我們釋放一個(gè)指針,然后再使用它。這是一個(gè)大錯(cuò)誤。讓我們問一下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)
這里的一切再次變得清晰。
在投入生產(chǎn)之前,請(qǐng)使用內(nèi)存調(diào)試器。正如您在本章中學(xué)到的那樣,您在計(jì)算中忘記的小字節(jié)可能導(dǎo)致可利用的安全漏洞。它還經(jīng)常(非常頻繁地)導(dǎo)致簡(jiǎn)單的崩潰。這意味著您的擴(kuò)展很酷,可以減少整個(gè)服務(wù)器(服務(wù)器)及其每個(gè)客戶端的數(shù)量。
C是一種非常嚴(yán)格的編程語(yǔ)言。您將獲得數(shù)十億字節(jié)的內(nèi)存來進(jìn)行編程,并且必須安排這些內(nèi)存來執(zhí)行一些計(jì)算。但是請(qǐng)不要搞砸這種強(qiáng)大的功能:在最好的情況下(罕見),什么都不會(huì)發(fā)生,在更壞的情況下(非常常見),您會(huì)在這里和那里隨機(jī)崩潰,在最壞的情況下,您會(huì)創(chuàng)建一個(gè)漏洞在恰好可以被遠(yuǎn)程利用的程序中...
您的工具嫻熟,聰明,請(qǐng)確實(shí)照顧機(jī)器內(nèi)存。
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。