Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

ZendGuardLoader + Gallery3 = segmentation fault?
post by tommy @ 20 十二月, 2011 12:36

如果你在有使用 Zend Guard Loader 的網站中架設 Gallery 3 的話, 在跑完 install 的畫面之後, 你就會發現你的 Gallery 3 永遠都出現一個空白畫面. 這問題... 有人在 Gallery 那邊問, 想當然的.... 得到一個不是我們的問題的答案 (如果我是作者, 我也會這樣回答的), 也有人在 Zend 那邊問, 結果與我以前問 Zend 問題的經驗一樣.... 完全沒有任何作用.

解決方法, 其實很簡單, 那就是不要用 ZendGuardLoader.so 就好了 (別罵了, 我也知道這是什麼屁方法....).

原則上, 這是 ZendGaurdLoader 的問題, 由於這東西是人家賣的某產品的要用到的 loader, 並不是什麼 open source 的東西, 自然... 沒人會知道這東西是怎麼做的, 也沒有辦法自行去修改, 所以.... 有問題的請儘量去找 Zend 這家公司吧. 不過... 雖然這家公司算是 PHP 這東西的核心公司 (要說是 PHP 的爸爸也可以), 不過... 我懷疑目前他們到底有多少懂 PHP 底層的開發人員在負責 Zend Guard 這東西, 光一個支援 PHP 5.3 的版本, 可以在一年多後還看不到影子 (別的類似產品的公司, 早就提供這個支援了), 好不容易終於生出了 ZendGuard 5.5 及相關的 loader 可以支援 PHP 5.3, 不過.... 看起來發生 segmentation fault 的情形並不算少數. 所以.... 這問題人家反應至少有半年了, 沒什麼下聞看起來也還算正常吧 (反正沒期待就不會受傷害).

如果你一定要用到 ZendGaurdLoader.so, 那... 由於這玩意並不能動態的載入, 只能在一開始執行 PHP 時就決定要不要載入這類的模組, 所以.... 如果你是用 Apache 加上 php 使用 module 的方式執行的話, 那.... 無解, 請再弄一台機器, 把需要用到 ZendGuardLoader 的程式與在 ZendGaurdLoader 中會有問題的程式分開來跑吧.

如果不行.... 那看能不能改成 CGI 或 FPM 的方式來跑 PHP, 把這些 CGI/FPM 的 daemon 指定不同的 port 或 socket file, 然後指定使用不同的 php.ini (在這兒決定要不要載入 ZendGuardLoader.so), 最後... 把需要 ZendGaurdLoader 的往有支援的那一個送, 這樣至少同一台機器中, 可以各取所需.

如果還是不行.... 那, 就修改你的程式吧, 看能不能避掉這問題.... 以我碰到的例子 (就是 Galley 3 這程式), 通常... 這問題發生在 autoload 的處理上頭, 當搭配 autoload 使用時, 如果要去判斷一個 class 或其中某個 method 是否存在時 (就是使用 class_exists()method_exists() 去判斷), 這類的程式會做一個 autoload 的動作, 嘗試去載入相關的定義檔.... 但是如果真的沒有那個檔案存在, 在沒有 ZendGaurdLoader 時, 會去執行一次 spl_autoload_register() 的 function, 然後就回覆 false. 但是... 如果有 ZendGuardLoader 時, 會對同一個 class 或 method 去執行那個 autoload 的 function, 且第三次傳入的 class 名稱是一個亂數, 然後.... 程式就會出現 segmentation fault 就掛了.

要避免這問題, 一個就是大幅改寫程式, 儘量不要用 autoload 的方式處理. (我知道很難... 比重寫還麻煩)

另一個是偷吃步.... 在 autoload 處理時, 如果那個 class 的定義檔案是不存在的, 就產生一個 dummy 的 class 給系統 (反正不存在表示之後也不會用到), 讓系統以為有這個 class (只是沒有任何 property 與 method), 這樣就可以避開這個 bug.

以 Gallery 3 來說:

--- gallery3.orig/system/core/Kohana.php        2011-05-25 12:04:04.000000000 +0800
+++ gallery3/system/core/Kohana.php 2011-12-20 21:59:20.901236982 +0800
@@ -698,6 +698,26 @@
else
{
// The class could not be found
+ // twu2 begin
+ // avoid segmentation fault in Zend Guard
+ // because when ZendGuardLoader enable, it will try to load the same class again if it's not exist, then... it will try a random name, then segmentation fault
+ // so we keep the name first, then if it try again
+ // create a dummy class for it
+ //
+ // only check this if ZendGuardLoader exist
+ if (extension_loaded('Zend Guard Loader')) {
+ static $last_name = '';
+
+ // reject it first
+ if ($last_name !== $class) {
+ $last_name = $class;
+ return FALSE;
+ }
+ // create dummy one if try again
+ Kohana_Log::add('debug', 'create dummy class: '.$class);
+ eval("class $class { }");
+ }
+ // twu2 end
return FALSE;
}

這個改法, 可以在不存在該 class 定義時, 建一個空的 class 來用. 這樣子的處理, 就可以讓 Gallery 3 避開 ZendGuardLoader 的 bug 了. 不過... 最好的方法, 還是不要一起用吧.

PS. 上頭的改法, 原本直接產生的方式, 會造成 g2_import 不正常, 因為 g2_import 會載入的 class 並不放在 G3 這系統下, 所以... 解決方法是不去處理 G2 的 class (只能碰到一個就加一個), 或... 改成目前的方式, 反正出問題時, 會連續對同一個 class 做兩次這動作 (正常情形下, 不過有沒有都應該只做一次), 最後一個奇怪名字的 class 後才 segmentation fault. 所以... 就把名字記下來, 重複的第二次才去產生那個 dummy class, 這樣子看起來就正常了. (也許之後還會有問題.... 所以最好是分開來, 不要一起用吧, 把 ZendGuardLoader 用在只需要它的地方就好了)

Del.icio.us Furl HEMiDEMi Technorati MyShare
迴響
暱稱:
標題:
個人網頁:
電子郵件:
authimage

迴響

  

Bad Behavior 已經阻擋了 57 個過去 7 天試圖闖關的垃圾迴響與引用。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS