This is an archive of the discontinued LLVM Phabricator instance.

[clang][Analyzer] Handle flexible arrays better in ArrayBoundV2 checker.
Needs ReviewPublic

Authored by balazske on Apr 1 2021, 3:22 AM.

Details

Summary

This is an experimental fix for ArrayBoundV2 checker to handle "flexible arrays"
(incomplete array) better. If incomplete array is found to be indexed, the
used size (for out-of-bounds check) will be the dynamic size of base region,
with offset (of the incomplete array) taken into account.
In this was indexing of incomplete arrays is not reported as error,
if the array was allocated using a fixed size.

Diff Detail

Event Timeline

balazske created this revision.Apr 1 2021, 3:22 AM
balazske requested review of this revision.Apr 1 2021, 3:22 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 1 2021, 3:22 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

The tests are really promising! :)

clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
117

Do we need an overload perhaps in DynamicSize.h of

SVal getDynamicSizeWithOffset(ProgramStateRef State, const SVal &BufV)

that takes a MemRegion?

It works not reliable for all data types. If char is used instead of int (in the test), the allocated size may be larger than the intended size of the array, probably because memory alignment adjustments. In the following case it is possible to index "past the end" of the array for some first indices (until 12?).

struct S {
  int n;
  char x;
  char s[];
};
struct S *s = (struct S *)malloc(sizeof(struct S) + 10);
s.s[12] = 12;
clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
117

If the change is accepted then yes, or have only the MemRegion version.

It works not reliable for all data types. If char is used instead of int (in the test), the allocated size may be larger than the intended size of the array, probably because memory alignment adjustments. In the following case it is possible to index "past the end" of the array for some first indices (until 12?).

struct S {
  int n;
  char x;
  char s[];
};

struct S *s = (struct S *)malloc(sizeof(struct S) + 10);
s.s[12] = 12;

Then I suppose we have to consider the alignment info as well. Perhaps you could reuse some parts of the PlacementNewChecker's alignment checking implementation? (see https://github.com/llvm/llvm-project/blob/main/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp#L176 ) I'd do that only in second follow-up patch, because that is going to complicate things.

martong added inline comments.Apr 1 2021, 6:30 AM
clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
117

I think this is the other way around, let's create the overload then we accept.