环境准备
git reset--hard df52b65dba782a6bbef0b64684795bcea3503607gclient sync
Patch分析
diff --git a/src/compiler/type-cache.h b/src/compiler/type-cache.hindex ada95a3..2ade5f6 100644--- a/src/compiler/type-cache.h+++ b/src/compiler/type-cache.h@@ -80,7 +80,7 @@Type::Union(kPositiveIntegerOrMinusZero, Type::NaN(), zone());Type const kAdditiveSafeInteger =- CreateRange(-4503599627370496.0, 4503599627370496.0);+ CreateRange(-4503599627370495.0, 4503599627370495.0);Type const kSafeInteger = CreateRange(-kMaxSafeInteger, kMaxSafeInteger);Type const kAdditiveSafeIntegerOrMinusZero =Type::Union(kAdditiveSafeInteger, Type::MinusZero(), zone());
poc是把kAdditiveSafeInteger这个const的范围给更新了一下,根据名字来看应该是做加法的整数的安全范围,反向查找一下引用,发现也只有在这里被引用了一次,还有一次是在下面对kAdditiveSafeIntegerOrMinusZero的赋值,仅此两次。
然后继续反向找一下kAdditiveSafeIntegerOrMinusZero,发现在compiler/simplified-lowering.cc下有几个引用,具体做什么用现在现在还不是很清楚。
issue里面给了POC ,先来分析这个POC。
POC分析
// the first function exists to generate the SpeculativeSafeIntegerAdd nodefunctionbar(a,b) {a = a|0;b = b|0;var x = a*(2**30) + b; // constrain x to be an integerx = Math.min(Math.max(x,0),4503599627370496) // further constrain to kAdditiveSafeIntegerreturn (x+x)|0; // the actual addition, plus the truncation to Word32}functionfoo(a,b) {a = a|0;a = Math.min(Math.max(a,4194304),4194304);b = b|0;b = Math.min(Math.max(b,2**30-2),2**30); // these constraints will mean that x has type Range(4503599627370496, 4503599627370496)// the result of bar will be typed to the intersection of// Range(-9007199254740991, 9007199254740991) and Range(9007199254740992, 9007199254740992)// which is empty; the dead code elimination emits a Throwreturn bar(a,b);}%PrepareFunctionForOptimization(bar);bar(0,1,0);%OptimizeFunctionOnNextCall(bar);bar(0,1,0);%PrepareFunctionForOptimization(foo);console.log(foo(0,2**29-1));%OptimizeFunctionOnNextCall(foo);console.log(foo(0,2**29-1));
根据POC的写法,猜测是Type的BUG,运行一下看一下
发现凭空插入一个断点,我们来分析下这个错误是如何生产的。
漏洞分析
trace-turbo 生成IR图,直接对IR操作。查看最终生成的代码。
发现这里意外有个unreachable,显然是BUG生成的。然后看下schedule阶段。
不出所料果然是有个unreachable,然后查看一下这个节点的起源。
#180节点在 simplified lowering 阶段被替换。那就去找下。
发现这边还有一个209 也是。在后面没有原因应该是代码亢余消除阶段给消了。
对#209节点重复上面操作。发现是在typerlowering阶段替换的。而此时我们看到了未被替换的修改的#180节点也就是#227的前身。
继续查找,发现#209 是在这个阶段被DeadCodeElimination生成的。
然后看下上面一个阶段,发现其还未被替换。
至于为什么被替换,根据issue给的解释是因为#180的两个valueinput也就是上图显示的#202节点下面的range,两个传入的都是4503599627370496,也就是patch修改之后的值,然后两个#202 被 #180操作之后为9007199254740992,超过 kMaxSafeInteger=9007199254740991,溢出了一个1,正好因为这个1导致了#180的type 被设置为了None。然后由于type 的错误,后面的也会被设置为None,然后在typerlowering阶段的DeadCodeElimination里面由于#180的none ,然后由于#180 作为#181的effect,所以在这被替换为unreachable。(patch之后 计算的值在合适的范围内就不会产生BUG)。
然后在simplelowering 阶段 #180由于range为none,而最终被替换成unreachable。
然后在simplelowering 阶段 #180由于range为none,而最终被替换成unreachable。
至此分析完毕。