簡體   English   中英

在PHP 7.4異常的源代碼中使用__wakeup有什么意義?

[英]What's the point of having __wakeup in source code of PHP 7.4 Exceptions?

有一種(相當新的)利用技術,稱為phar 反序列化 ,它由PHP的文件系統功能(file_existsunlink ,...)觸發,然后在實例化的類中執行未序列化的代碼,該類至少需要包含兩種魔術方法之一__wakeup__destruct

我的想法是在PHP的源代碼中搜索內置的PHP類,這些類可能具有此類方法的本地實現( __wakeup__destruct ),並且可以在異常處理期間的反序列化過程中以某種方式利用(可能觸發某些使用-釋放后的錯誤)。 實際上,我在幾個Exception類中找到了__wakeup (獲取所有內置類並檢查它們是否具有__wakeup__destruct方法的簡便方法是使用PHP函數get_declared_classes() )。 但是目前看來,這是無法解釋的。

因此,問題不在於開發事物。

問題:我不明白為什么要在異常 __wakeup實現__wakeup 它只是用於擴展此類Exception類並稍后編寫自己的__wakeup / __destruct方法的占位符方法嗎?

源代碼: https : //github.com/php/php-src/blob/master/Zend/zend_exceptions.c#L316

在306-333行( php-src / Zend / zend_exceptions.c ,PHP 7.4)中:

/* }}} */

/* {{{ proto Exception::__wakeup()
   Exception unserialize checks */
#define CHECK_EXC_TYPE(id, type) \
    pvalue = zend_read_property_ex(i_get_exception_base(object), (object), ZSTR_KNOWN(id), 1, &value); \
    if (Z_TYPE_P(pvalue) != IS_NULL && Z_TYPE_P(pvalue) != type) { \
        zend_unset_property(i_get_exception_base(object), object, ZSTR_VAL(ZSTR_KNOWN(id)), ZSTR_LEN(ZSTR_KNOWN(id))); \
    }

ZEND_METHOD(exception, __wakeup)
{
    zval value, *pvalue;
    zval *object = ZEND_THIS;
    CHECK_EXC_TYPE(ZEND_STR_MESSAGE,  IS_STRING);
    CHECK_EXC_TYPE(ZEND_STR_STRING,   IS_STRING);
    CHECK_EXC_TYPE(ZEND_STR_CODE,     IS_LONG);
    CHECK_EXC_TYPE(ZEND_STR_FILE,     IS_STRING);
    CHECK_EXC_TYPE(ZEND_STR_LINE,     IS_LONG);
    CHECK_EXC_TYPE(ZEND_STR_TRACE,    IS_ARRAY);
    pvalue = zend_read_property(i_get_exception_base(object), object, "previous", sizeof("previous")-1, 1, &value);
    if (pvalue && Z_TYPE_P(pvalue) != IS_NULL && (Z_TYPE_P(pvalue) != IS_OBJECT ||
            !instanceof_function(Z_OBJCE_P(pvalue), zend_ce_throwable) ||
            pvalue == object)) {
        zend_unset_property(i_get_exception_base(object), object, "previous", sizeof("previous")-1);
    }
}
/* }}} */

及以后的第788-801行: https : //github.com/php/php-src/blob/master/Zend/zend_exceptions.c#L788

static const zend_function_entry default_exception_functions[] = {
    ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
    ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
    ZEND_ME(exception, __wakeup, NULL, ZEND_ACC_PUBLIC)
    ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
    ZEND_ME(exception, __toString, NULL, 0)
    ZEND_FE_END
};

據我所知,這段代碼正在驗證異常屬性的類型,如果類型不正確,則將它們設置為null 例如:

CHECK_EXC_TYPE(ZEND_STR_MESSAGE,  IS_STRING);

大致等同於PHP代碼:

if (!is_string($this->message))
    $this->message = null;

同樣,以pvalue = zend_read_property(…)開頭的結尾的代碼正在檢查$this->previous是實現Throwable的對象。 在PHP中,它大致等同於:

if (!is_object($this->previous) || !($this->previous instanceof Throwable)
    $this->previous = null;

至於為什么此代碼是PHP解釋器的一部分? Exception類的全部在此處用C代碼定義。 內置類或方法都不是用PHP編寫的-不能這樣,因為該語言無法將方法的PHP實現安裝到用C聲明的類中。

我想說的是,由於Exception類應該是可反序列化的,因此它需要已經在C級別添加了__wakeup()方法(因為Exception類的屬性也已在C中定義)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM