除了最常见的if条件语句之外,条件句还可以用运算符来表示。
三元运算符 ?:
?:
是唯一的三元运算符。
1 |
|
对应的CPG为:
我更喜欢转成规整的树状图查看:
上面的代码相当于:
1 |
|
对应的CFG为:
我们可以看到,id=10
的节点是statement $b=$a
的根节点,id=17
是statement $b=1
的根节点。
php7新特性——null合并运算符??
而在php7中,也有一些新的特性引入,具体可以参看下面这2篇文章:
php7中引入了一些新特性,比如:
Scalar type declarations:标量类型声明
Return type declarations:返回值类型声明
Null coalescing operator:null合并运算符,
??
Spaceship operator:太空船操作符(组合比较符),
<=>
Constant arrays using define():(通过define()定义常量数组)
Anonymous classes:匿名类
Unicode codepoint escape syntax:Unicode codepoint转译语法
and so on …
其中,和条件语句相关的新特性是null合并运算符
,通常用??
来表示,比如源码:
1 |
|
用null合并运算表示符来表示就是:
1 |
|
我用PHP-Parser解析后得到的AST树是这样的:
1 | array( |
更具象点,用php-ast-visualizer可视化后的AST树为:
这个ast树其实和下面的源码对应的ast是一模一样的:
1 |
|
但是这并不是合法的php语法,因为$firstName
是未定义的,编译执行的时候会报错:
1 | php test.php |
报错原因为:https://blog.csdn.net/mnmnwq/article/details/82465985
nodes.csv
rels.csv
生成的代码属性图为:
用更清晰的图来表示为:
其中结点id=8, type=AST_COALESCE
的结点就是表示??
运算符,但是该结点被当成了顺序语句。在上图中并没有体现出分支的情况。
问题小结
上面的两个cases中,问题在于,PHPJoern将AST_CONDITION
和AST_COALESCE
节点当成了普通的赋值节点。如果我们真的要改进也很困难,像上面提到的正常的分支语句,我们能找到分支所需要的根节点,但是对于这种情况,我们找不到根节点,因为php2ast
在将php文件解析为抽象语法树的时候,压根就没将其当成分支语句,所以没有解析出可用的分支节点,那Joern自然也无法根据php2ast解析的结果来处理这样特殊的条件语句。
如果说Joern无法正确处理三元运算条件语句和null合并运算符是因为没有分支需要的根节点,那么我们可以尝试将源码改成:
1 |
|
得到的代码属性图为:
转化为我自己更喜欢的图就是:
可以看到,在这种情况下,还是按照顺序语句处理。但是对于这种情况,是可以优化Joern的,我们自己也可以画出正确的控制流(我认为的正确的画法):