manas added inline comments.
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1397
+ (LHS.To() < 0 && RHS.To() < 0 && Max > 0) ||
+ (LHS.To() < 0 && RHS.To() < 0 && Max > 0)) {
+ return {RangeFactory, Tmin, Tmax};
----------------
vsavchenko wrote:
> This clause is exactly the same as the previous one, it is a mistake.
> And I think we should have a test that could've shown that.
> Also, since you are checking for overflows for both the beginning and the
> end, we should have tests where both overflow.
Understood! I will add tests to check each OR part of these conditionals in
these cases.
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1401-1402
+
+ // FIXME: This case in particular is resulting in failed assertion.
+ Range First = Range(Tmin, Max);
+ Range Second = Range(Min, Tmax);
----------------
vsavchenko wrote:
> vsavchenko wrote:
> > manas wrote:
> > > I changed the logic from using getCrucialPoints (which I mentioned in the
> > > e-mail thread) to simple checks to determine overflows using signedness.
> > > But the failed assertions again popped up. And I was unable to pin-point
> > > the issue here. Can someone help me?
> > >
> > > Although, I am thinking of revising the above logic by using bitwise
> > > methods to detect overflows.
> > This is actually one place that I won't expect an assertion failure.
> > Can we get a bit more detail on it? Is it again `From > To` (which will
> > indeed be weird) or something different?
> >
> > NOTE: Asking for help (either here or on StackOverflow) is a lot like
> > filing a bug report, try to put as much information as possible, try to
> > structure this information so it is easy to follow. It's also good to tell
> > people what you tried, instead of saying that you tried something and it
> > didn't work.
> OK, I downloaded your patch and ran the debugger.
>
> It complains about different bit-width for ranges that the analyzer tries to
> intersect. What I checked next: what are those ranges, so I took `begin()`
> from one of them and checked what are `From` and `To` there.
> Here is one of them:
> ```
> (const llvm::APSInt) $8 = {
> llvm::APInt = {
> U = {
> VAL = 22
> pVal = 0x0000000000000016
> }
> BitWidth = 4022311424
> }
> IsUnsigned = true
> }
> ```
> Woah, this `BitWidth` seems ridiculous! What does it tell us? It definitely
> didn't get there as part of any reasonable logic, right? So, what can it be
> instead? Only one answer here - garbage. We have some sort of memory issue
> with integers that we use as part of our ranges! So, let's see what type of
> information `Range` class actually stores:
> ```
> class Range {
> public:
> Range(const llvm::APSInt &From, const llvm::APSInt &To) : Impl(&From, &To) {
> assert(From <= To);
> }
>
> ...
>
> private:
> std::pair<const llvm::APSInt *, const llvm::APSInt *> Impl;
> };
> ```
>
> What we have here is a pair of pointers, and you have:
> ```
> llvm::APSInt Min = LHS.From() + RHS.From();
> llvm::APSInt Max = LHS.To() + RHS.To();
> llvm::APSInt Tmin = ValueFactory.getMinValue(ResultType);
> llvm::APSInt Tmax = ValueFactory.getMaxValue(ResultType);
> ```
> These are ALL stack variables. So, pointer to those point to adequate data
> ONLY while we are inside of our functions. When we call another function,
> these pointers point into some data from some other function in the call
> stack, it doesn't point to anything even remotely resembling `llvm::APSInt`
> and we get `BitWidth = 4022311424`.
>
> OK, we figured out the problem, what about a solution? If you look at other
> implementations, you can notice a couple of interesting things.
> When you do:
> ```
> llvm::APSInt Tmin = ValueFactory.getMinValue(ResultType);
> ```
> other code does something like:
> ```
> const llvm::APSInt &Tmin = ValueFactory.getMinValue(ResultType);
> ```
> Or when you do:
> ```
> Range Second = Range(Min, Tmax);
> ```
> The sibling code does:
> ```
> return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
> ```
>
> It looks like `ValueFactory` is the key here! It actually manages the
> lifetime of those integers for you and, whenever you ask it about values, it
> gives you `llvm::APSInt &` (note the reference part) that will have the
> correct lifetime.
>
> I hope this gives you some insight into how you can debug things like this on
> your own and how you can reason about what you see.
>
> Another piece of advice is to look around, other `VisitBinaryOperator`
> methods have all the information you actually needed. If you don't
> understand why we need `ValueFactory`, - experiment, ask us! It's bad to
> just ignore it.
Got it! I am working on fixing this.
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1405-1406
+ RangeSet ResultRangeSet = RangeFactory.getRangeSet(First);
+ RangeSet ResultRangeSet2 = RangeFactory.add(ResultRangeSet, Second);
+ return ResultRangeSet2;
+ }
----------------
vsavchenko wrote:
> Why not just `return RangeFactory.add(ResultRangeSet, Second)`?
>
> NOTE: variables with integers in their names is a big no-no.
Right! I assumed I have to refactor this part so I used this temporarily.
================
Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1409-1415
+ if ((LHS.From() > 0 && RHS.From() > 0 && Min < 0) ||
+ (LHS.From() < 0 && RHS.From() < 0 && Min > 0) ||
+ (LHS.To() > 0 && RHS.To() > 0 && Max < 0) ||
+ (LHS.To() < 0 && RHS.To() < 0 && Max > 0)) {
+ // return [Tmin, Tmax]
+ return {RangeFactory, Tmin, Tmax};
+ }
----------------
vsavchenko wrote:
> I thought we talked quite a lot that there is nothing bad with overflows and
> here we have that if ANY overflow happened, we bail out and don't give any
> result.
Understood! Should I replace it with code returning EmptySet()?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D103440/new/
https://reviews.llvm.org/D103440
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits