php7下的opcache特性導致的乙個bug排查

2021-07-08 10:06:28 字數 1476 閱讀 2299

首先這不是opcache的bug,我感覺這算是新特性導致**不太相容導致的,因為我們的**在php5下是跑正常的。

最近在給我們的框架相容php7,因為框架是擴充套件的形式,所以得針對新版的zend api修改。

一些都ok了,在cli測試都是沒問題的,感覺很爽。

但是放到了php-fpm的環境下,開啟opcache。一些亂七八糟的事情發生了,fpm啟動後第一次請求是正常,第二次後就各種segmentfault了。所以就有了前面的一篇文章:

到底發生啥事了?

場景是這樣的,大家都清楚一般的php的mvc框架裡面,都會有乙個自動載入函式來實現類庫的用時載入,而不用事先的include進來。沒錯,我們的框架裡面也有這個乙個函式,這個函式是c函式,因為框架是以擴充套件的形式編寫的。導致bug相關的一段**如下:

class_name這個變數就是需要的類名,請記住這貨。

獲得這個class_name後,會有針對這個class_name的一系列操作,比如這段**:

可以看到,畫紅線的部分,先是對這個class_name_str指標指向class_name字元位址,然後接著一系列的操作這塊字串的操作。比如分割strtok 等操作。這時候class_name結構體對應的字串指標已經被改得面目全非了,已經不是傳入引數的原始值了。其實這也沒什麼問題,因為邏輯需要,所以才需要各種擷取和改變這塊位址的字串。

當opcache來了之後,一切都變了。

opcache是記錄php編譯的中間**的乙個擴充套件,以致於下次請求來時不需要執行編譯操作從而達到加速的目的。

接著上面的話題,當使用opcache之後,opcache連同傳入的類名,也就是上面的class_name的結構也儲存了,也就是上面對class_name做的任何修改都儲存下來了。所以,當下一次呼叫的時候,傳入的只是擷取後的值。比如我的類名是if_paramvalidator。當經過strtok 擷取後,只剩下了if了,所以下次呼叫的時候,傳進來的只有if而不是if_paramvalidator。然後再去擷取字串「if」的時候,擷取規則如圖:

所以,file這個變數獲得的值依然是null。然後下面有乙個操作file[0] = toupper(file[0])。對非法記憶體解引用必然導致segmentfault了。

所以,導致了第一次請求正常,第二次後就崩了。

這個問題在php7的opcache下才存在,在php5版本我們的框架跑得是正常的。

所以各位親們,如果你的擴充套件裡面有搭配opcache使用的,一定要注意這個特點,opcache快取起來的zval結構或者任何物件是持久化的,當你的擴充套件對外界傳來的引數進行修改時,一定要複製乙份。

PHP7如何開啟opcache擴充套件

opcache 說白了就是將php源 進行快取,而不再需要編譯二進位制。php7預設已經安裝了opcahe拓展,只需要開啟即可 vim usr local php etc php.ini zend extension opcache.so cli環境下,php啟用opcache opcache.en...

PHP7開啟opcache打造強悍效能

鳥哥在部落格中說,提高php 7效能的幾個tips,第一條就是開啟opcache 記得啟用zend opcache,因為php7即使不啟用opcache速度也比php 5.6啟用了opcache快,所以之前測試時期就發生了有人一直沒有啟用opcache的事情 那麼什麼是opcache呢?opcach...

PHP7開啟opcache打造強悍效能

鳥哥在部落格中說,提高php 7效能的幾個tips,第一條就是開啟opcache 記得啟用zend opcache,因為php7即使不啟用opcache速度也比php 5.6啟用了opcache快,所以之前測試時期就發生了有人一直沒有啟用opcache的事情 那麼什麼是opcache呢?opcach...