Skip to content

Commit 4c29a60

Browse files
authored
Revert "[clang][dataflow] Transfer more cast expressions." (llvm#157148)
Reverts llvm#153066 copyRecord crashes if copying from the RecordStorageLocation shared by the base/derived objects after a DerivedToBase cast because the source type is still `Derived` but the copy destination could be of a sibling type derived from Base that has children not present in `Derived`. For example, running the dataflow analysis over the following produces UB by nullptr deref, or fails asserts if enabled: ```cc struct Base {}; struct DerivedOne : public Base { int DerivedOneField; }; struct DerivedTwo : public Base { int DerivedTwoField; DerivedTwo(const DerivedOne& d1) : Base(d1), DerivedTwoField(d1.DerivedOneField) {} }; ``` The constructor initializer for `DerivedTwoField` serves the purpose of forcing `DerivedOneField` to be modeled, which is necessary to trigger the crash but not the assert failure.
1 parent 16661b5 commit 4c29a60

File tree

3 files changed

+13
-349
lines changed

3 files changed

+13
-349
lines changed

clang/include/clang/Analysis/FlowSensitive/StorageLocation.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include "clang/AST/Decl.h"
1818
#include "clang/AST/Type.h"
1919
#include "llvm/ADT/DenseMap.h"
20-
#include "llvm/ADT/StringRef.h"
2120
#include "llvm/Support/Debug.h"
2221
#include <cassert>
2322

@@ -153,11 +152,6 @@ class RecordStorageLocation final : public StorageLocation {
153152
return {SyntheticFields.begin(), SyntheticFields.end()};
154153
}
155154

156-
/// Add a synthetic field, if none by that name is already present.
157-
void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc) {
158-
SyntheticFields.insert({Name, &Loc});
159-
}
160-
161155
/// Changes the child storage location for a field `D` of reference type.
162156
/// All other fields cannot change their storage location and always retain
163157
/// the storage location passed to the `RecordStorageLocation` constructor.
@@ -170,11 +164,6 @@ class RecordStorageLocation final : public StorageLocation {
170164
Children[&D] = Loc;
171165
}
172166

173-
/// Add a child storage location for a field `D`, if not already present.
174-
void addChild(const ValueDecl &D, StorageLocation *Loc) {
175-
Children.insert({&D, Loc});
176-
}
177-
178167
llvm::iterator_range<FieldToLoc::const_iterator> children() const {
179168
return {Children.begin(), Children.end()};
180169
}

clang/lib/Analysis/FlowSensitive/Transfer.cpp

Lines changed: 12 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,14 @@
2020
#include "clang/AST/OperationKinds.h"
2121
#include "clang/AST/Stmt.h"
2222
#include "clang/AST/StmtVisitor.h"
23-
#include "clang/AST/Type.h"
2423
#include "clang/Analysis/FlowSensitive/ASTOps.h"
2524
#include "clang/Analysis/FlowSensitive/AdornedCFG.h"
2625
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
2726
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
2827
#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
2928
#include "clang/Analysis/FlowSensitive/RecordOps.h"
30-
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
3129
#include "clang/Analysis/FlowSensitive/Value.h"
3230
#include "clang/Basic/Builtins.h"
33-
#include "clang/Basic/LLVM.h"
3431
#include "clang/Basic/OperatorKinds.h"
3532
#include "llvm/Support/Casting.h"
3633
#include <assert.h>
@@ -290,7 +287,7 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
290287
}
291288
}
292289

293-
void VisitCastExpr(const CastExpr *S) {
290+
void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
294291
const Expr *SubExpr = S->getSubExpr();
295292
assert(SubExpr != nullptr);
296293

@@ -320,70 +317,17 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
320317
break;
321318
}
322319

323-
case CK_BaseToDerived: {
324-
// This is a cast of (single-layer) pointer or reference to a record type.
325-
// We should now model the fields for the derived type.
326-
327-
// Get the RecordStorageLocation for the record object underneath.
328-
RecordStorageLocation *Loc = nullptr;
329-
if (S->getType()->isPointerType()) {
330-
auto *PV = Env.get<PointerValue>(*SubExpr);
331-
assert(PV != nullptr);
332-
if (PV == nullptr)
333-
break;
334-
Loc = cast<RecordStorageLocation>(&PV->getPointeeLoc());
335-
} else {
336-
assert(S->getType()->isRecordType());
337-
if (SubExpr->isGLValue()) {
338-
Loc = Env.get<RecordStorageLocation>(*SubExpr);
339-
} else {
340-
Loc = &Env.getResultObjectLocation(*SubExpr);
341-
}
342-
}
343-
if (!Loc) {
344-
// Nowhere to add children or propagate from, so we're done.
345-
break;
346-
}
347-
348-
// Get the derived record type underneath the reference or pointer.
349-
QualType Derived = S->getType().getNonReferenceType();
350-
if (Derived->isPointerType()) {
351-
Derived = Derived->getPointeeType();
352-
}
353-
354-
// Add children to the storage location for fields (including synthetic
355-
// fields) of the derived type and initialize their values.
356-
for (const FieldDecl *Field :
357-
Env.getDataflowAnalysisContext().getModeledFields(Derived)) {
358-
assert(Field != nullptr);
359-
QualType FieldType = Field->getType();
360-
if (FieldType->isReferenceType()) {
361-
Loc->addChild(*Field, nullptr);
362-
} else {
363-
Loc->addChild(*Field, &Env.createStorageLocation(FieldType));
364-
}
365-
366-
for (const auto &Entry :
367-
Env.getDataflowAnalysisContext().getSyntheticFields(Derived)) {
368-
Loc->addSyntheticField(Entry.getKey(),
369-
Env.createStorageLocation(Entry.getValue()));
370-
}
371-
}
372-
Env.initializeFieldsWithValues(*Loc, Derived);
373-
374-
// Fall through to propagate SubExpr's StorageLocation to the CastExpr.
375-
[[fallthrough]];
376-
}
377320
case CK_IntegralCast:
378321
// FIXME: This cast creates a new integral value from the
379322
// subexpression. But, because we don't model integers, we don't
380323
// distinguish between this new value and the underlying one. If integer
381324
// modeling is added, then update this code to create a fresh location and
382325
// value.
383326
case CK_UncheckedDerivedToBase:
384-
case CK_DerivedToBase:
385327
case CK_ConstructorConversion:
386328
case CK_UserDefinedConversion:
329+
// FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
330+
// CK_ConstructorConversion, and CK_UserDefinedConversion.
387331
case CK_NoOp: {
388332
// FIXME: Consider making `Environment::getStorageLocation` skip noop
389333
// expressions (this and other similar expressions in the file) instead
@@ -740,6 +684,15 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
740684
propagateValue(*SubExpr, *S, Env);
741685
}
742686

687+
void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
688+
if (S->getCastKind() == CK_NoOp) {
689+
const Expr *SubExpr = S->getSubExpr();
690+
assert(SubExpr != nullptr);
691+
692+
propagateValueOrStorageLocation(*SubExpr, *S, Env);
693+
}
694+
}
695+
743696
void VisitConditionalOperator(const ConditionalOperator *S) {
744697
const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
745698
const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());

0 commit comments

Comments
 (0)