Skip to content

Commit e800823

Browse files
authored
Merge pull request #8647 from gottesmm/tighten_verification_of_inouttopointer_arraytopointer
[ast-verifier] Verify that inout_to_pointer and array_to_pointer are (almost) immediate children of an ApplyExpr argument.
2 parents 290ecde + 244f1f6 commit e800823

File tree

1 file changed

+201
-68
lines changed

1 file changed

+201
-68
lines changed

lib/AST/ASTVerifier.cpp

Lines changed: 201 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,28 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17-
#include "swift/Subsystems.h"
18-
#include "swift/AST/AccessScope.h"
1917
#include "swift/AST/ASTContext.h"
2018
#include "swift/AST/ASTWalker.h"
19+
#include "swift/AST/AccessScope.h"
2120
#include "swift/AST/Decl.h"
2221
#include "swift/AST/Expr.h"
23-
#include "swift/AST/Module.h"
24-
#include "swift/AST/ParameterList.h"
25-
#include "swift/AST/Pattern.h"
26-
#include "swift/AST/Stmt.h"
2722
#include "swift/AST/ForeignErrorConvention.h"
2823
#include "swift/AST/GenericEnvironment.h"
2924
#include "swift/AST/Initializer.h"
25+
#include "swift/AST/Module.h"
26+
#include "swift/AST/ParameterList.h"
27+
#include "swift/AST/Pattern.h"
3028
#include "swift/AST/PrettyStackTrace.h"
3129
#include "swift/AST/ProtocolConformance.h"
30+
#include "swift/AST/Stmt.h"
3231
#include "swift/Basic/SourceManager.h"
32+
#include "swift/Subsystems.h"
3333
#include "llvm/ADT/SmallBitVector.h"
3434
#include "llvm/ADT/SmallString.h"
35+
#include "llvm/Support/Debug.h"
3536
#include "llvm/Support/raw_ostream.h"
3637
#include <functional>
38+
#include <type_traits>
3739
using namespace swift;
3840

3941
namespace {
@@ -71,69 +73,147 @@ struct ASTNodeBase {};
7173
};
7274
#include "swift/AST/PatternNodes.def"
7375

74-
class Verifier : public ASTWalker {
75-
PointerUnion<ModuleDecl *, SourceFile *> M;
76-
ASTContext &Ctx;
77-
llvm::raw_ostream &Out;
78-
const bool HadError;
79-
SmallVector<bool, 8> InImplicitBraceStmt;
80-
81-
/// \brief The stack of functions we're visiting.
82-
SmallVector<DeclContext *, 4> Functions;
83-
84-
/// \brief The stack of scopes we're visiting.
85-
using ScopeLike = llvm::PointerUnion<DeclContext *, BraceStmt *>;
86-
SmallVector<ScopeLike, 4> Scopes;
87-
88-
/// The set of primary archetypes that are currently available.
89-
SmallVector<GenericEnvironment *, 2> GenericEnv;
90-
91-
/// \brief The stack of optional evaluations active at this point.
92-
SmallVector<OptionalEvaluationExpr *, 4> OptionalEvaluations;
93-
94-
/// \brief The set of opaque value expressions active at this point.
95-
llvm::DenseMap<OpaqueValueExpr *, unsigned> OpaqueValues;
76+
template <typename Ty>
77+
struct is_apply_expr
78+
: public std::integral_constant<
79+
bool,
80+
std::is_same<Ty, CallExpr>::value ||
81+
std::is_same<Ty, PrefixUnaryExpr>::value ||
82+
std::is_same<Ty, PostfixUnaryExpr>::value ||
83+
std::is_same<Ty, BinaryExpr>::value ||
84+
std::is_same<Ty, DotSyntaxCallExpr>::value ||
85+
std::is_same<Ty, ConstructorRefCallExpr>::value> {};
86+
87+
template <typename Ty>
88+
struct is_autoclosure_expr
89+
: public std::integral_constant<bool,
90+
std::is_same<Ty, AutoClosureExpr>::value> {
91+
};
92+
93+
template <typename Ty>
94+
struct is_apply_or_autoclosure_expr
95+
: public std::integral_constant<
96+
bool, is_apply_expr<Ty>::value || is_autoclosure_expr<Ty>::value> {};
97+
98+
template <typename Verifier, typename Kind>
99+
std::pair<bool, Expr *> dispatchVisitPreExprHelper(
100+
Verifier &V,
101+
typename std::enable_if<
102+
is_apply_expr<typename std::remove_pointer<Kind>::type>::value,
103+
Kind>::type node) {
104+
if (V.shouldVerify(node)) {
105+
// Whitelist any inout_to_pointer or array_to_pointer that we see in
106+
// the proper position.
107+
V.updateExprToPointerWhitelist(node, node->getArg());
108+
return {true, node};
109+
}
110+
V.cleanup(node);
111+
return {false, node};
112+
}
96113

97-
/// The set of opened existential archetypes that are currently
98-
/// active.
99-
llvm::DenseSet<ArchetypeType *> OpenedExistentialArchetypes;
114+
template <typename Verifier, typename Kind>
115+
std::pair<bool, Expr *> dispatchVisitPreExprHelper(
116+
Verifier &V,
117+
typename std::enable_if<
118+
is_autoclosure_expr<typename std::remove_pointer<Kind>::type>::value,
119+
Kind>::type node) {
120+
if (V.shouldVerify(node)) {
121+
// Whitelist any inout_to_pointer or array_to_pointer that we see in
122+
// the proper position.
123+
V.updateExprToPointerWhitelist(node, node->getSingleExpressionBody());
124+
return {true, node};
125+
}
126+
V.cleanup(node);
127+
return {false, node};
128+
}
100129

101-
/// A key into ClosureDiscriminators is a combination of a
102-
/// ("canonicalized") local DeclContext* and a flag for whether to
103-
/// use the explicit closure sequence (false) or the implicit
104-
/// closure sequence (true).
105-
typedef llvm::PointerIntPair<DeclContext*,1,bool> ClosureDiscriminatorKey;
106-
llvm::DenseMap<ClosureDiscriminatorKey,
107-
llvm::SmallBitVector> ClosureDiscriminators;
108-
DeclContext *CanonicalTopLevelContext = nullptr;
130+
template <typename Verifier, typename Kind>
131+
std::pair<bool, Expr *> dispatchVisitPreExprHelper(
132+
Verifier &V, typename std::enable_if<
133+
!is_apply_or_autoclosure_expr<
134+
typename std::remove_pointer<Kind>::type>::value,
135+
Kind>::type node) {
136+
if (V.shouldVerify(node)) {
137+
return {true, node};
138+
}
139+
V.cleanup(node);
140+
return {false, node};
141+
}
109142

110-
Verifier(PointerUnion<ModuleDecl *, SourceFile *> M, DeclContext *DC)
143+
class Verifier : public ASTWalker {
144+
PointerUnion<ModuleDecl *, SourceFile *> M;
145+
ASTContext &Ctx;
146+
llvm::raw_ostream &Out;
147+
const bool HadError;
148+
SmallVector<bool, 8> InImplicitBraceStmt;
149+
150+
/// \brief The stack of functions we're visiting.
151+
SmallVector<DeclContext *, 4> Functions;
152+
153+
/// \brief The stack of scopes we're visiting.
154+
using ScopeLike = llvm::PointerUnion<DeclContext *, BraceStmt *>;
155+
SmallVector<ScopeLike, 4> Scopes;
156+
157+
/// The set of primary archetypes that are currently available.
158+
SmallVector<GenericEnvironment *, 2> GenericEnv;
159+
160+
/// \brief The stack of optional evaluations active at this point.
161+
SmallVector<OptionalEvaluationExpr *, 4> OptionalEvaluations;
162+
163+
/// \brief The set of opaque value expressions active at this point.
164+
llvm::DenseMap<OpaqueValueExpr *, unsigned> OpaqueValues;
165+
166+
/// The set of opened existential archetypes that are currently
167+
/// active.
168+
llvm::DenseSet<ArchetypeType *> OpenedExistentialArchetypes;
169+
170+
/// The set of inout to pointer expr that match the following pattern:
171+
///
172+
/// (call-expr
173+
/// (brace-stmt
174+
/// ... maybe other arguments ...
175+
/// (inject_into_optional
176+
/// (inout_to_pointer ...))
177+
/// ... maybe other arguments ...))
178+
///
179+
/// Any other inout to pointer expr that we see is invalid and the verifier
180+
/// will assert.
181+
llvm::DenseSet<InOutToPointerExpr *> WhitelistedInOutToPointerExpr;
182+
llvm::DenseSet<ArrayToPointerExpr *> WhitelistedArrayToPointerExpr;
183+
184+
/// A key into ClosureDiscriminators is a combination of a
185+
/// ("canonicalized") local DeclContext* and a flag for whether to
186+
/// use the explicit closure sequence (false) or the implicit
187+
/// closure sequence (true).
188+
typedef llvm::PointerIntPair<DeclContext *, 1, bool> ClosureDiscriminatorKey;
189+
llvm::DenseMap<ClosureDiscriminatorKey, llvm::SmallBitVector>
190+
ClosureDiscriminators;
191+
DeclContext *CanonicalTopLevelContext = nullptr;
192+
193+
Verifier(PointerUnion<ModuleDecl *, SourceFile *> M, DeclContext *DC)
111194
: M(M),
112195
Ctx(M.is<ModuleDecl *>() ? M.get<ModuleDecl *>()->getASTContext()
113-
: M.get<SourceFile *>()->getASTContext()),
114-
Out(llvm::errs()),
115-
HadError(Ctx.hadError())
116-
{
117-
Scopes.push_back(DC);
118-
GenericEnv.push_back(DC->getGenericEnvironmentOfContext());
119-
}
120-
121-
public:
122-
Verifier(ModuleDecl *M, DeclContext *DC)
123-
: Verifier(PointerUnion<ModuleDecl *, SourceFile *>(M), DC) { }
124-
Verifier(SourceFile &SF, DeclContext *DC)
125-
: Verifier(&SF, DC) { }
196+
: M.get<SourceFile *>()->getASTContext()),
197+
Out(llvm::errs()), HadError(Ctx.hadError()) {
198+
Scopes.push_back(DC);
199+
GenericEnv.push_back(DC->getGenericEnvironmentOfContext());
200+
}
126201

127-
static Verifier forDecl(const Decl *D) {
128-
DeclContext *DC = D->getDeclContext();
129-
DeclContext *topDC = DC->getModuleScopeContext();
130-
if (auto SF = dyn_cast<SourceFile>(topDC))
131-
return Verifier(*SF, DC);
132-
return Verifier(topDC->getParentModule(), DC);
133-
}
202+
public:
203+
Verifier(ModuleDecl *M, DeclContext *DC)
204+
: Verifier(PointerUnion<ModuleDecl *, SourceFile *>(M), DC) {}
205+
Verifier(SourceFile &SF, DeclContext *DC) : Verifier(&SF, DC) {}
206+
207+
static Verifier forDecl(const Decl *D) {
208+
DeclContext *DC = D->getDeclContext();
209+
DeclContext *topDC = DC->getModuleScopeContext();
210+
if (auto SF = dyn_cast<SourceFile>(topDC))
211+
return Verifier(*SF, DC);
212+
return Verifier(topDC->getParentModule(), DC);
213+
}
134214

135-
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
136-
switch (E->getKind()) {
215+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
216+
switch (E->getKind()) {
137217
#define DISPATCH(ID) return dispatchVisitPreExpr(static_cast<ID##Expr*>(E))
138218
#define EXPR(ID, PARENT) \
139219
case ExprKind::ID: \
@@ -243,7 +323,6 @@ struct ASTNodeBase {};
243323
llvm_unreachable("Unhandled declaration kind");
244324
}
245325

246-
private:
247326
/// Helper template for dispatching pre-visitation.
248327
/// If we're visiting in pre-order, don't validate the node yet;
249328
/// just check whether we should stop further descent.
@@ -255,13 +334,11 @@ struct ASTNodeBase {};
255334
}
256335

257336
/// Helper template for dispatching pre-visitation.
337+
///
258338
/// If we're visiting in pre-order, don't validate the node yet;
259339
/// just check whether we should stop further descent.
260340
template <class T> std::pair<bool, Expr *> dispatchVisitPreExpr(T node) {
261-
if (shouldVerify(node))
262-
return { true, node };
263-
cleanup(node);
264-
return { false, node };
341+
return dispatchVisitPreExprHelper<Verifier, T>(*this, node);
265342
}
266343

267344
/// Helper template for dispatching pre-visitation.
@@ -1089,7 +1166,14 @@ struct ASTNodeBase {};
10891166
void verifyChecked(InOutToPointerExpr *E) {
10901167
PrettyStackTraceExpr debugStack(Ctx,
10911168
"verifying InOutToPointer", E);
1092-
1169+
1170+
if (!WhitelistedInOutToPointerExpr.count(E)) {
1171+
Out << "Unwhitelisted InOutToPointerExpr?!\n";
1172+
E->print(Out);
1173+
Out << "\n";
1174+
abort();
1175+
}
1176+
10931177
auto fromElement = E->getSubExpr()->getType()->getInOutObjectType();
10941178
auto toElement = E->getType()->getAnyPointerElementType();
10951179

@@ -1116,6 +1200,13 @@ struct ASTNodeBase {};
11161200
PrettyStackTraceExpr debugStack(Ctx,
11171201
"verifying ArrayToPointer", E);
11181202

1203+
if (!WhitelistedArrayToPointerExpr.count(E)) {
1204+
Out << "ArrayToPointer in invalid position?!\n";
1205+
E->print(Out);
1206+
Out << "\n";
1207+
abort();
1208+
}
1209+
11191210
// The source may be optionally inout.
11201211
auto fromArray = E->getSubExpr()->getType()->getInOutObjectType();
11211212

@@ -1249,6 +1340,48 @@ struct ASTNodeBase {};
12491340
verifyCheckedBase(E);
12501341
}
12511342

1343+
void updateExprToPointerWhitelist(Expr *Base, Expr *Arg) {
1344+
auto handleSubExpr = [&](Expr *SubExpr) {
1345+
// if we have an inject into optional, strip it off.
1346+
if (auto *InjectIntoOpt = dyn_cast<InjectIntoOptionalExpr>(SubExpr)) {
1347+
SubExpr = InjectIntoOpt->getSubExpr();
1348+
}
1349+
1350+
if (auto *InOutToPtr = dyn_cast<InOutToPointerExpr>(SubExpr)) {
1351+
WhitelistedInOutToPointerExpr.insert(InOutToPtr);
1352+
return;
1353+
}
1354+
1355+
if (auto *ArrayToPtr = dyn_cast<ArrayToPointerExpr>(SubExpr)) {
1356+
WhitelistedArrayToPointerExpr.insert(ArrayToPtr);
1357+
}
1358+
};
1359+
1360+
// If we have a tuple_shuffle, strip it off. We want to visit the
1361+
// underlying paren or tuple expr.
1362+
if (auto *TupleShuffle = dyn_cast<TupleShuffleExpr>(Arg)) {
1363+
Arg = TupleShuffle->getSubExpr();
1364+
}
1365+
1366+
if (auto *ParentExprArg = dyn_cast<ParenExpr>(Arg)) {
1367+
return handleSubExpr(ParentExprArg->getSubExpr());
1368+
}
1369+
1370+
if (auto *TupleArg = dyn_cast<TupleExpr>(Arg)) {
1371+
for (auto *SubExpr : TupleArg->getElements()) {
1372+
handleSubExpr(SubExpr);
1373+
}
1374+
return;
1375+
}
1376+
1377+
// Otherwise, just run it through handle sub expr. This case can happen if
1378+
// we have an autoclosure.
1379+
if (isa<AutoClosureExpr>(Base)) {
1380+
handleSubExpr(Arg);
1381+
return;
1382+
}
1383+
}
1384+
12521385
void verifyChecked(ApplyExpr *E) {
12531386
PrettyStackTraceExpr debugStack(Ctx, "verifying ApplyExpr", E);
12541387

0 commit comments

Comments
 (0)