tomasz-kaminski-sonarsource added inline comments.

================
Comment at: clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp:204
+    // subtraction/addition of the negated value.
+    if (!RHS.isNegative()) {
+      ConvertedRHS = &BasicVals.Convert(resultTy, RHS);
----------------
steakhal wrote:
> tomasz-kaminski-sonarsource wrote:
> > steakhal wrote:
> > > I would rather swap these branches though, to leave the default case 
> > > (aka. this) to the end.
> > I folded the `RHS.isNegative()` into the if for the 
> > `BinaryOperator::isAssociative(op)`, as same conversion is performed in 
> > final else branch.
> I think what confused me is that a different API is used for doing the 
> conversion.
>  - `resultIntTy.convert(RHS)`
>  - `&BasicVals.Convert(resultTy, RHS)`
> 
> Anyway, leave it as-is.
As a note, the use of different APIs was intentional. The `BasicVals` one is 
persisting the value, so it is safe to use ptr to it, as a consequence it is 
more costfull. So, I am delaying its use until I know I will need to persist 
the value.


================
Comment at: clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp:212-219
+      llvm::APSInt ConvertedRHSValue = resultIntTy.convert(RHS);
+      // Check if the negation of the RHS is representable,
+      // i.e., the resultTy is signed, and it is not the lowest
+      // representable negative value.
+      if (ConvertedRHSValue > resultIntTy.getMinValue()) {
+        ConvertedRHS = &BasicVals.getValue(-ConvertedRHSValue);
+        op = (op == BO_Add) ? BO_Sub : BO_Add;
----------------
steakhal wrote:
> tomasz-kaminski-sonarsource wrote:
> > tomasz-kaminski-sonarsource wrote:
> > > steakhal wrote:
> > > > Somehow I miss a check for signedness here.
> > > > Why do you think it would be only triggered for signed types?
> > > > 
> > > > I have a guess, that since we already handled `x +-0`, SymIntExprs like 
> > > > `x - (-0)` cannot exist here, thus cannot trigger this condition 
> > > > spuriously. I cannot think of any ther example that could cause this 
> > > > misbehaving. So in that sense `ConvertedRHSValue > 
> > > > resultIntTy.getMinValue()` implies *at this place* that 
> > > > `ConvertedRHSValue.isSigned()`.
> > > > I would rather see this redundant check here to make the correctness 
> > > > reasoning local though.
> > > The integer representation does not have negative zeros (the standard and 
> > > clang assume two's complement). However, this condition does need to 
> > > check for the signedness of the types. What I mean is that if the `RHS` 
> > > is negative, but `ConvertedRHSValue` the branch will trigger and we will 
> > > change `x - INT_MIN` to `x + (INT_MAX + 1)U` which is ok, as a negation 
> > > of `INT_MIN` is representable as an unsigned type of same or lager bit 
> > > with.
> > > 
> > However, I was not able to reach this point with `RHS` being signed, and 
> > `resultTy` being unsigned. Any hints how this could be done?
> I'm not saying that I can follow this thought process. But the 
> `clang/test/Analysis/PR49642.c` would trigger an assertion like this:
> 
> ```lang=diff
> diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp 
> b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
> index 088c33c8e612..7e59309228e1 100644
> --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
> +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
> @@ -207,6 +207,16 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
>             "number of bits as its operands.");
>  
>      llvm::APSInt ConvertedRHSValue = resultIntTy.convert(RHS);
> +    if (RHS.isSigned() && resultTy->isUnsignedIntegerOrEnumerationType()) {
> +      llvm::errs() << "LHS sym:\n";
> +      LHS->dump();
> +      llvm::errs() << "RHS integral:\n";
> +      RHS.dump();
> +      llvm::errs() << "OP: " << BinaryOperator::getOpcodeStr(op) << "\n";
> +      llvm::errs() << "result type:\n";
> +      resultTy->dump();
> +      llvm_unreachable("how is it possible??");
> +    }
>      // Check if the negation of the RHS is representable,
>      // i.e., the resultTy is signed, and it is not the lowest
>      // representable negative value.
> ```
> 
> Which can be reduced into this one:
> 
> ```lang=c
> // RUN: %clang_analyze_cc1 -Wno-implicit-function-declaration -w -verify %s \
> // RUN:   -analyzer-checker=core \
> // RUN:   -analyzer-checker=apiModeling.StdCLibraryFunctions
> 
> // expected-no-diagnostics
> 
> typedef int ssize_t;
> int write(int, const void *, unsigned long);
> unsigned c;
> void a() {
>   int b = write(0, 0, c);
>   b != 0;
>   c -= b;
>   b < 1;
>   ++c; // crash simplifySValOnce: derived_$4{conj_$1{int, LC1, S700, #1},c}  
> op(-)  APInt(32b, 4294967295u -1s)  :: unsigned int
> }
> ```
What I mean, is that performing normalization (op and sign switch) is always 
correct for the unsigned `resultInTy`, even if `RHS` is the lowest 
representable negative number. The code is already behaving correctly in that 
case (I have verified your example), as the `ConvertedRHSValue > 
resultIntTy.getMinValue()` is always passing in a situation when 
`resultIntTy.isUnsigned()` is true (zero was eliminated before), so I left 
simple check.

But, now I see that this is confusing, so I have updated the check to be more 
explicit and updated the comment.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124658/new/

https://reviews.llvm.org/D124658

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to