This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] Warn if the size of the array in `new[]` is undefined
ClosedPublic

Authored by isuckatcs on Aug 5 2022, 2:46 PM.

Details

Summary

@martong I kept your idea in mind for this warning message and implemented it as a new checker if you don't mind it.

If the size of an array is Undefined when it's allocated, this patch emits a warning, and ends the analysis.

Diff Detail

Event Timeline

isuckatcs created this revision.Aug 5 2022, 2:46 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 5 2022, 2:46 PM
isuckatcs requested review of this revision.Aug 5 2022, 2:46 PM
NoQ added a comment.Aug 6 2022, 3:49 PM

Oh thanks a lot for handling this case!

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
1527

Expressions cannot be of reference type. They use value kinds instead (lvalue, xvalue, etc). So I suspect your tests pass without this check.

NoQ added inline comments.Aug 6 2022, 3:49 PM
clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
1508

A slightly more natural way to do this in path-sensitive analysis is to invoke

const auto *ACE = dyn_cast<CXXAllocatorCall>(&Call);

and then use that subclass's accessor methods to access values.

It doesn't look like this subclass actually provides an accessor for the size value though. We should add one!

Maybe also add a getter that asks whether the call is for new[] vs. new, and then assert that it's new[] in the size value getter.

2293–2296

I think making it a separate checker is slightly better. It's more natural to group it together with the uninitialized variable checks than with memory leak / use-after-free checks.

Like, generally, I wish we had a more flexible system of "hashtags" that could allow us to group checkers in different ways, probably overlapping (so this check could be #NewDelete #UninitializedVariable). But that's a story for another time :D

2313

I believe you can simply add a trackExpressionValue() instead. It'll display where the value comes from through path notes.

isuckatcs updated this revision to Diff 450803.Aug 8 2022, 7:39 AM
isuckatcs marked 4 inline comments as done.
isuckatcs retitled this revision from [analyzer][MallocChecker] Warn if the size of the array in `new[]` is undefined to [analyzer] Warn if the size of the array in `new[]` is undefined.
isuckatcs edited the summary of this revision. (Show Details)
  • Addressed comments
  • Separated the checker from MallocChecker to a new one
isuckatcs added inline comments.Aug 8 2022, 7:39 AM
clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
2313

I've added it but I also left this message. If someone only runs clang++ --analyze source.cpp then I think it feels better to receive a bit more descriptive warning message.

isuckatcs updated this revision to Diff 450805.Aug 8 2022, 7:41 AM

Fixed a typo

xazax.hun added inline comments.Aug 8 2022, 9:06 AM
clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
28

I think we no longer need this mutable lazy initialized BugType hack. See FuchsiaHandleChecker.cpp for an example. While we no longer need this hack, we have not cleaned up the existing checks yet :(

40

I think we could add a convenience function to CXXAllocatorCall that would return an SVal for the size expression.

xazax.hun added inline comments.Aug 8 2022, 9:07 AM
clang/test/Analysis/undefined-new-element.cpp
2

Is there a comment missing here?

isuckatcs updated this revision to Diff 450841.Aug 8 2022, 9:30 AM
isuckatcs marked 3 inline comments as done.

Addressed comments

isuckatcs added inline comments.Aug 8 2022, 9:31 AM
clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
28

I'm not really familiar with checker developement. Why did we need this hack?

clang/test/Analysis/undefined-new-element.cpp
2

This checker is in alpha.core at the moment. Should I just put it directly to core instead?

xazax.hun added inline comments.Aug 8 2022, 9:35 AM
clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
28

Long story short, we need lazy initialization because some information is only available when a bug is reported (and not when the check is initialized). This is due to the architecture of CSA. In the old times the lazy initialization was the responsibility of the checks and later we moved this hack to the engine itself to make writing checks easier and cleaner.

clang/test/Analysis/undefined-new-element.cpp
2

I might be missing something, but I found it surprising that the RUN line in line 2 is not commented out while the RUN line in line 3 is.

isuckatcs updated this revision to Diff 450851.Aug 8 2022, 9:44 AM
isuckatcs marked 2 inline comments as done.

Addressed comments

clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
28

I see, thanks for the explanation.

clang/test/Analysis/undefined-new-element.cpp
2

Oh, that is a typo I didn't notice. I moved the whole command into one line instead, it's short enough for that I think.

xazax.hun accepted this revision.Aug 8 2022, 9:47 AM
This revision is now accepted and ready to land.Aug 8 2022, 9:47 AM

I am not sure whether we actually use exclamation marks in diagnostic texts. Otherwise this looks good to me. Maybe adding expected-note's to the test would be nice, but overall this looks good to me.

NoQ added a comment.Aug 8 2022, 11:44 AM

Great!

I think this checker can be turned on by default pretty quickly. We should run it over some code but other than that it seems to be in good shape from the start.

I agree with Gabor, we don't usually have exclamation marks in warnings. It could definitely be exciting to have exclamation marks! But I'm worried that since clang is part of multiple finished GUI products, various UI/UX review boards won't be happy with us for that :( So we limit exclamation marks to assertion failures. Side note, clang warning style and grammar doesn't seem to be documented anywhere. Side note, static analyzer warning style and grammar is completely different from clang warning style and grammar (we expect our warnings to be complete sentences).

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
313

Maybe alpha.core.uninitialized then, with the intent to eventually put it into core.uninitialized?

clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
1038–1040

This function doesn't seem to ever return None (?)

1043–1045

I think it's cleaner to assert(isArray()) here and avoid the optional. The caller would do something like

if (!Call->isArray())
  return;

SVal V = Call->getArraySizeVal();

and it communicates the intent behind the code much nicer.

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
2313

If someone only runs clang++ --analyze source.cpp then I think it feels better to receive a bit more descriptive warning message.

Most static analyzer warnings are barely ever understandable without path notes, your extra text won't help much most of the time. We basically don't support running the static analyzer without reading path notes, so I think we should ignore this scenario. Especially given that this facility doesn't cover all the cases so it may make diagnostics look worse.

It's definitely weird that such basic invocation is unsupported. I think we should flip the default output to --analyzer-output text, but it may break backwards compatibility in weird ways because the current default output is actually plist (so the command you quoted will produce a weird .plist file in the current directory as an output) so IDEs can run this command and consume this machine-readable output.

clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
32

I recommend checkPreCall. This will cause the new checker to run *before* MallocChecker. It's also generally natural to check preconditions in PreCall and evaluate postconditions in PostCall.

@martong I kept your idea in mind for this warning message and implemented it as a new checker if you don't mind it. If the size of an array is Undefined when it's allocated, this patch emits a warning, and ends the analysis.

Thank you for taking care of this!

clang/test/Analysis/undefined-new-element.cpp
43–46

I think it would make sense to have a test for an array placement new expression as well.
Something like:

int n;
void* buffer = malloc(sizeof(std::string) * 10);
std::string* p = ::new (buffer) std::string[n]; // expected-warning{{Undefined element count!}}
isuckatcs updated this revision to Diff 451502.Aug 10 2022, 8:48 AM
isuckatcs marked 6 inline comments as done.

Addressed comments

isuckatcs updated this revision to Diff 451506.Aug 10 2022, 8:50 AM

Updated

clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
1038–1040

getArraySize() returns an Optional<const clang::Expr *>, so it can return None.

NoQ added a comment.Aug 11 2022, 12:20 AM

Ok I have some warning text bikeshedding but generally the patch looks great and the checker should probably be enabled by default from the start, or otherwise very soon.

clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
29

Let's point out that we're talking about new[]:

"Undefined array element count in new[]"
50

It's probably easier to do this inside the function.

62

Static analyzer warnings are traditionally full sentences. Let's make this more complete:

"Element count in new[] is a garbage value"

(it also avoids the term "undefined", which we typically avoid and we should have probably avoided in UndefinedArraySubscriptChecker as well; it's not precise enough, may be confusing)

isuckatcs updated this revision to Diff 451762.Aug 11 2022, 1:25 AM
isuckatcs marked 3 inline comments as done.

Addressed comments

clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
50

I prefer to keep the logics separated, so it's more obvious which part of the code is doing what.

isuckatcs added inline comments.Aug 22 2022, 11:01 AM
clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
1752

This doesn't fix any known bugs, I've just noticed that it's error prone and fixed it in this patch.

Looks great!

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
450

This line suggests that this checker is documented at the checkers.rst, however, I cannot see the corresponding entry.

clang/test/Analysis/undefined-new-element.cpp
9

IDK, it's probably personal, but I dislike newlines here. And it also feels weird that in the llvm coding style we have the curly openings at the line endings instead of at the next line.

isuckatcs updated this revision to Diff 455109.Aug 24 2022, 1:59 AM
isuckatcs marked 2 inline comments as done.

Added a documentation into checkers.rst.

clang/test/Analysis/undefined-new-element.cpp
9

I like the newlines there. Also I reformatted this file with the llvm style.

isuckatcs updated this revision to Diff 455112.Aug 24 2022, 2:30 AM

Fixed docs build error

isuckatcs updated this revision to Diff 455533.Aug 25 2022, 4:22 AM

Fixed the broken test file. Clang-format put a line break between {{ and }} and that caused the failure.

NoQ added a comment.EditedAug 30 2022, 10:54 AM
This comment has been deleted.
clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
80

You can use mgr.getLangOpts().CPlusPlus to avoid registering the checker on non-C++ translation units.

clang/test/Analysis/undefined-new-element.cpp
2

Let's make sure tracking works by adding -analyzer-output=text.

isuckatcs updated this revision to Diff 456814.Aug 30 2022, 3:56 PM
isuckatcs marked 2 inline comments as done.
  • Addressed comments
  • Moved the checker to core from alpha.core
NoQ accepted this revision.Sep 1 2022, 8:51 PM

Looks great. I agree that it can go straight to core because our undefined value checkers are roughly all the same and we're already pretty good at writing them. The checker appears to be very quiet in my experience, I'm yet to see a warning in the wild, but I think the path note tests give enough signal that warnings are going to look good.

I have one tiny nitpick that should be addressed before committing.

clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
63

Static analyzer warnings start with a capital letter! The idea is that they're complete sentences, unlike compiler warnings.

isuckatcs updated this revision to Diff 457728.Sep 2 2022, 4:01 PM
isuckatcs marked an inline comment as done.

Addressed the nit

isuckatcs updated this revision to Diff 457788.Sep 3 2022, 6:24 AM

Updated the documentation

Herald added a project: Restricted Project. · View Herald TranscriptSep 4 2022, 2:07 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript