This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] Ignore calculated indices of <= 0 in VLASizeChecker
ClosedPublic

Authored by vabridgers on May 31 2020, 5:29 PM.

Details

Summary

See https://bugs.llvm.org/show_bug.cgi?id=46128. The checker does not
yet comprehend constraints involving multiple symbols, so it's possible
to calculate a VLA size that's negative or 0. A LIT is added to catch
regressions, and this change simply bails if a VLA size of 0 or less is
calculated.

Diff Detail

Event Timeline

vabridgers created this revision.May 31 2020, 5:29 PM

Not sure this is "correct", but it passes LITs with the new case, and it will at least get the discussion started :)

Address some typos

NoQ added inline comments.Jun 1 2020, 4:04 AM
clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
114–115

Do i understand correctly that this cast is the only difference between the value that has been checked and the value on which the assertion is asserted?

vabridgers added inline comments.Jun 1 2020, 5:11 PM
clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
114–115

Yes, looks that way to me. Let's see if Balasz, Gabor, Adam or Kristof responds in the next day or two? Thanks Artem!

balazske added inline comments.Jun 1 2020, 11:46 PM
clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
114–115

Yes the cast is the difference. Even if this problem is fixed (cast included in checkVLAIndexSize) the same problem happens.
The following code (in checkVLAIndexSize) prints (reg_$0<int a>) + 1 0 before the crash. So there is some difference between assume and getKnownValue. It can be better to include check of getKnownValue in checkVLAIndexSize (at least for zero value).

// Convert the array length to size_t.
NonLoc SizeNL =
    SVB.evalCast(SizeD, SizeTy, SizeE->getType()).castAs<NonLoc>();

// Check if the size is zero.
ProgramStateRef StateNotZero, StateZero;
std::tie(StateNotZero, StateZero) = State->assume(SizeNL);

if (StateZero && !StateNotZero) {
  reportBug(VLA_Zero, SizeE, StateZero, C);
  return nullptr;
}

// From this point on, assume that the size is not zero.
State = StateNotZero;

if (const llvm::APSInt *IndexLVal = SVB.getKnownValue(State, SizeNL)) {
  uint64_t L = IndexLVal->getZExtValue();
  llvm::errs() << SizeNL << " " << L << "\n";
  assert(L != 0);
}
NoQ added inline comments.Jun 2 2020, 3:00 AM
clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
114–115

It might be that simplifySVal isn't applied consistently. Like, assume() fails to apply it so it fails to see that the value is in fact concrete zero.

Let's remove the assertion for now and add a FIXME to investigate why can't we add it back. Like, there's nothing preventing us from investigating it now but it will take some time whereas crashes are already there and we should fix them to unblock other people.

It is no problem to return instead of the assert. I could fix the problem by using

SVal LessThanZeroVal = SVB.evalBinOp(State, BO_LE, SizeD, Zero, SizeTy);

in checkVLAIndexSize (BO_LT is used before). Still the proposed return makes the code more safe.

clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
129–134

The assert does not look good if there is already the check before.

130

I do not know if this is accurate reason for the problem, a more general text is better? And should start with uppercase.

131

Can be ==.

vabridgers updated this revision to Diff 267882.Jun 2 2020, 7:25 AM

Address comments from Artem and Balazs. This change just avoids the crash for now until a proper fix can be made.

balazske accepted this revision.Jun 2 2020, 8:24 AM

At least as fast bugfix it is acceptable.

This revision is now accepted and ready to land.Jun 2 2020, 8:24 AM
NoQ accepted this revision.Jun 2 2020, 10:06 AM

Thank you! Please commit :)

Szelethus accepted this revision.Jun 2 2020, 12:50 PM

LGTM! :)

Here is an improved fix for the problem: D81061

This revision was automatically updated to reflect the committed changes.