Make the SValBuilder capable to simplify existing
SVals based on a newly added constraints when evaluating a BinOp.
Before this patch, we called simplify only in some edge cases.
However, we can and should investigate the constraints in all cases.
Differential D113753
[Analyzer][Core] Better simplification in SimpleSValBuilder::evalBinOpNN martong on Nov 12 2021, 4:06 AM. Authored by
Details Make the SValBuilder capable to simplify existing Before this patch, we called simplify only in some edge cases.
Diff Detail
Event TimelineComment Actions I'm attaching the coverage of the new test file for the related change: 375 : // Constraints may have changed since the creation of a bound SVal. Check if 376 : // the values can be simplified based on those new constraints. 377 12 : SVal simplifiedLhs = simplifySVal(state, lhs); 378 12 : SVal simplifiedRhs = simplifySVal(state, rhs); 379 12 : if (auto simplifiedLhsAsNonLoc = simplifiedLhs.getAs<NonLoc>()) 380 12 : lhs = *simplifiedLhsAsNonLoc; 381 12 : if (auto simplifiedRhsAsNonLoc = simplifiedRhs.getAs<NonLoc>()) 382 12 : rhs = *simplifiedRhsAsNonLoc; 383 :
Comment Actions I'm attaching the coverage of the new test file for the related change: 375 : // Constraints may have changed since the creation of a bound SVal. Check if 376 : // the values can be simplified based on those new constraints. 377 12 : SVal simplifiedLhs = simplifySVal(state, lhs); 378 12 : SVal simplifiedRhs = simplifySVal(state, rhs); 379 12 : if (auto simplifiedLhsAsNonLoc = simplifiedLhs.getAs<NonLoc>()) 380 12 : lhs = *simplifiedLhsAsNonLoc; 381 12 : if (auto simplifiedRhsAsNonLoc = simplifiedRhs.getAs<NonLoc>()) 382 12 : rhs = *simplifiedRhsAsNonLoc; 383 : Comment Actions This seem to cause some weird results. Given this input: bar(short k) { k++; for (short f = 0; f < k; f++) ; (long)k << 16; } we get > clang --analyze --target=x86_64 'bbi-63538.c' bbi-63538.c:5:11: warning: The result of the left shift is undefined due to shifting '1' by '16', which is unrepresentable in the unsigned version of the return type 'long' [core.UndefinedBinaryOperatorResult] (long)k << 16; ~~~~~~~ ^ bbi-63538.c:5:11: warning: The result of the left shift is undefined due to shifting '2' by '16', which is unrepresentable in the unsigned version of the return type 'long' [core.UndefinedBinaryOperatorResult] (long)k << 16; ~~~~~~~ ^ bbi-63538.c:5:11: warning: The result of the left shift is undefined due to shifting '3' by '16', which is unrepresentable in the unsigned version of the return type 'long' [core.UndefinedBinaryOperatorResult] (long)k << 16; ~~~~~~~ ^ 3 warnings generated. Comment Actions Good catch @bjope ! Comment Actions Here is a smaller reproducer: void bar(short k) { ++k; // k1 = k0 + 1 assert(k == 1); // k1 == 1 --> k0 == 0 (long)k << 16; // k0 + 1 << 16 } And the explanation is the following. With this patch, when the analyzer evaluates the (long)k << 16 expression then it can properly deduce the value of k being 1. However, it was not possible in the baseline. Since we do not model neither promotion nor explicit casts we get the false positive report. This issue highlights the importance of the patch stack to implement the modeling of casts (starting with https://reviews.llvm.org/D99797).
|
@martong, you simplified the operands, but you overwrite only the lhs and rhs. Shouldnt you overwite these as well?
What is the purpose of these variables, do you know?