This is an archive of the discontinued LLVM Phabricator instance.

[analyzer] Initialize regions returned by CXXNew to undefined
ClosedPublic

Authored by Szelethus on Oct 6 2022, 10:32 AM.

Details

Summary

Discourse mail: https://discourse.llvm.org/t/analyzer-why-do-we-suck-at-modeling-c-dynamic-memory/65667

malloc() returns a piece of uninitialized dynamic memory. We were (almost) always able to model this behaviour. Its C++ counterpart, operator new is a lot more complex, because it allows for initialization, the most complicated of which is the usage of constructors.

We gradually became better in modeling constructors, but for some reason, most likely for reasons lost in history, we never actually modeled the case when the memory returned by operator new was just simply uninitialized. This patch (attempts) to fix this tiny little error.

Diff Detail

Event Timeline

Szelethus created this revision.Oct 6 2022, 10:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 6 2022, 10:32 AM
Szelethus requested review of this revision.Oct 6 2022, 10:32 AM

Just a note on the test files -- I've diverged from the usual stance of just changing what the new output is, to modifying the test files. The reason is that reading an undefined value is a fatal error, leading to the analyzer to stop analyzing prematurely, and I think these cases were trying to test something else, not uninitialized value usage.

Awesome!
Have you measured how often would this change introduce new garbage value warnings?
At the other side of the spectrum it could also hide reports, because it sinks the path too soon due to the falsely binding uninitialized value there.
WDYT?

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
957

Yeey, finally we will have this :D

I wonder if we could query from the ASTContext if we have a trivially constructible class typeor something as a first approximation.

clang/test/Analysis/NewDelete-checker-test.cpp
388–393

This change seems unrelated.
Could you elaborate on that?

clang/test/Analysis/new.cpp
179–180

You should probably adjust this comment.

Szelethus edited the summary of this revision. (Show Details)Oct 7 2022, 1:52 AM

Some early results:

https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?review-status=Unreviewed&review-status=Confirmed%20bug&detection-status=New&detection-status=Reopened&detection-status=Unresolved&is-unique=on&run=%2acxxnew_baseline&newcheck=%2acxxnew_patched&diff-type=New

I'm still waiting on a few projects, but this is something. A few reports from alpha.security.ArrayBound, I still need to look into that.

This report from core.uninitialized.Assign is interesting. First off, I'd appreciate if the "storing uninitialized value" was placed inside the notes about the call to QScopedArrayPointer's constructor. Otherwise, the report looks correct.

Not too happy about this report by core.CallAndMessage. Message 9 is placed on the line

applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));

Messag 10 talks about what happens in applyColorTransform, but the important thing happens at the evaluation of the argument, which is not described, so this isn't a very good bug report, can't tell whether its false.

Reports from core.UndefinedBinaryOperatorResult here and alpha.core.Conversion here are interesting, because there doesn't need to be caused by uninitialized dynamic memory, but rather the fact that the memory is being modeled at all. I suspect this is due us maybe discarding array size information or something similar when the value held in UnknownVal?

The rest of the reports seem nobrainder gains.

Interstingly, 3 reports are lost from alpha.security.ArrayBound, but I'm not sure how seriously do we take this checker.

Some early results:

https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?review-status=Unreviewed&review-status=Confirmed%20bug&detection-status=New&detection-status=Reopened&detection-status=Unresolved&is-unique=on&run=%2acxxnew_baseline&newcheck=%2acxxnew_patched&diff-type=New

I'm still waiting on a few projects, but this is something. A few reports from alpha.security.ArrayBound, I still need to look into that.

This report from core.uninitialized.Assign is interesting. First off, I'd appreciate if the "storing uninitialized value" was placed inside the notes about the call to QScopedArrayPointer's constructor. Otherwise, the report looks correct.

Not too happy about this report by core.CallAndMessage. Message 9 is placed on the line

applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));

Messag 10 talks about what happens in applyColorTransform, but the important thing happens at the evaluation of the argument, which is not described, so this isn't a very good bug report, can't tell whether its false.

Yes, I agree, this bug-report is hard to follow. Seems like the colorSpace argument from step 1 is flowing through step 10. I wonder if colorSpace at step 1 is evaluated as Undefined? Could that happen? Did you have this report before your change?

Reports from core.UndefinedBinaryOperatorResult here

This seems to be justified, at step 11 we initialize the variable with a negative value. I think, this has nothing to do with your changes.

and alpha.core.Conversion here are interesting, because there doesn't need to be caused by uninitialized dynamic memory, but rather the fact that the memory is being modeled at all. I suspect this is due us maybe discarding array size information or something similar when the value held in UnknownVal?

The rest of the reports seem nobrainder gains.

Interstingly, 3 reports are lost from alpha.security.ArrayBound, but I'm not sure how seriously do we take this checker.

I think these new reports and the lost reports are the result of the changed analysis paths. With your patch, there are new bug reports which introduce sink nodes which were not there previously. Consequently, the set of analyzed paths and thus the new results can be different.

martong added a comment.EditedOct 17 2022, 7:05 AM

I am happy with the change and with the result. However, this colorSpace related report is a bit concerning. Could you please check if colorSpace at step 1 is evaluated as Undefined? Could that happen? Or that is (should be) Unknown since that is a parameter of a top-level analyzed function? Did you have this report before your change? I think this would worth to be further analyzed, maybe just directing the analyzer to analyze only the QImage::convertedToColorSpace top-level function.

NoQ added a comment.EditedOct 20 2022, 10:36 PM

Yay I'm glad that you got to implement that!!

I'd appreciate if the "storing uninitialized value" was placed inside the notes about the call to QScopedArrayPointer's constructor.

It should not be placed inside the notes about the call to constructor, because it doesn't happen during constructor invocation. It happens during operator new invocation, which is strictly before the constructor.

I guess we could improve the note to specify that it was operator new that stored the value; this could help in general case as well.

Separately, there *should* be notes inside the constructor as well, about the fact that the constructor *did not* initialize the fields, even though it *could have* (it literally had one job!) - You know, your favorite problem for at least two unrelated reasons =)

Edit, never mind, the constructor wasn't supposed to initialize that data at all. We're talking about the poinee of the smart pointer, not the smart pointer itself. The pointee is a raw int and doesn't have a constructor.

Messag 10 talks about what happens in applyColorTransform, but the important thing happens at the evaluation of the argument, which is not described, so this isn't a very good bug report, can't tell whether its false.

Yeah looks like trackExpressionValue() wasn't able to track it inside transformationToColorSpace().

Seems like the issues mentioned above are real, but orthogonal to this patch. Would it be okay to address them in followup patches? @martong @NoQ

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
957

And a result skip the rest of this function?

clang/test/Analysis/NewDelete-checker-test.cpp
388–393

The test case in its original version would have emitted an uninitialized use report, which is fine, but the intention is to test double deletes, not uninitialized use, hence the seemingly unrelated change.

martong accepted this revision.Oct 25 2022, 7:25 AM

Seems like the issues mentioned above are real, but orthogonal to this patch. Would it be okay to address them in followup patches? @martong @NoQ

I am okay with it. Thanks!

This revision is now accepted and ready to land.Oct 25 2022, 7:25 AM
This revision was automatically updated to reflect the committed changes.
Szelethus marked an inline comment as done.

Commit rGde2547329b41ad6ea4ea876d12731bde5a6b64c5 accidentally refers to this review, but in fact it belongs to D148355.