当前位置:Gxlcms > PHP教程 > [科普小文章]php内核动态调试关于弱类型比较

[科普小文章]php内核动态调试关于弱类型比较

时间:2021-07-01 10:21:17 帮助过:16人阅读

0x00 前言

上期的三个白帽挑战题已经结束,但是大家依旧意犹未尽,讨论着 writeup 中的知识点,其中比较有意思的是关于php弱类型的:

array(0)>999999999

这个结果是true的。

群里各位大牛给了各种思考,和相关文章:

php.com/manual/zh/language.operators.comparison.php

但是基本都是别人给出的结论,我不太喜欢结论性的东西,这只让我知道了结果,并不知道为什么有这样的结果。

0x01 php动态调试(php5.6为例)

1.下载解压并安装

# wget http://cn2.php.com/distributions/php-5.6.0.tar.xz # xz -d php-5.6.0.tar.xz # tar vxf php-5.6.0.tar # cd php-5.6.0 # ./configure --enable-debug # make # sudo make install

2.相关文章推荐

《深入理解Zend执行引擎(PHP5)》

《使用vld查看OPCode》

《调式PHP源码》

0x02 OPCode分析

可以看出关键操作是IS_SMALLER,如果你仔细看过上面推荐文章就可以找到关键函数

ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */

0x03 gdb动态调试

注意红框内容,相信看过上边内容的都能看懂(ps:详细内容太多,请先学习推荐文章)

大致逻辑是两个参数进来经过zendi_convert_scalar_to_number函数处理,由于我们一个是数组一个是整形,所以两个参数类型和值都不变

#define zendi_convert_scalar_to_number(op, holder, result) if (op==result) { if (Z_TYPE_P(op) != IS_LONG) { convert_scalar_to_number(op TSRMLS_CC); } } else { switch (Z_TYPE_P(op)) { case IS_STRING: { if ((Z_TYPE(holder)=is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL(holder), &Z_DVAL(holder), 1)) == 0) { ZVAL_LONG(&(holder), 0); } (op) = &(holder); break; } case IS_BOOL: case IS_RESOURCE: ZVAL_LONG(&(holder), Z_LVAL_P(op)); (op) = &(holder); break; case IS_NULL: ZVAL_LONG(&(holder), 0); (op) = &(holder); break; case IS_OBJECT: (holder) = (*(op)); zval_copy_ctor(&(holder)); convert_to_long_base(&(holder), 10); if (Z_TYPE(holder) == IS_LONG) { (op) = &(holder); } break; } }

然后再次进入循环到达

} else if (Z_TYPE_P(op1)==IS_ARRAY) { ZVAL_LONG(result, 1); return SUCCESS; } else if (Z_TYPE_P(op2)==IS_ARRAY) { ZVAL_LONG(result, -1); return SUCCESS;

从opcode可以看到op2为array(0)所以这儿返回-1

最后(Z_LVAL_P(result) < 0)成立,返回true

if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) { return FAILURE; } ZVAL_BOOL(result, (Z_LVAL_P(result) < 0)); return SUCCESS;

转载请注明来自 L.N.'s blog 的《[科普小文章]php内核动态调试关于弱类型比较》

人气教程排行