Skip to content

Commit fc8af60

Browse files
Merge pull request swiftlang#10159 from adrian-prantl/143923367
[lldb] Fix use-after-free in Playgrounds
2 parents a04e121 + c64b06a commit fc8af60

File tree

12 files changed

+208
-22
lines changed

12 files changed

+208
-22
lines changed

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,7 @@ LLDBNameLookup::LLDBNameLookup(
138138
SwiftExpressionParser::SILVariableMap &variable_map, SymbolContext &sc,
139139
ExecutionContextScope &exe_scope)
140140
: SILDebuggerClient(source_file.getASTContext()),
141-
m_log(GetLog(LLDBLog::Expressions)), m_source_file(source_file),
142-
m_variable_map(variable_map), m_sc(sc) {
141+
m_source_file(source_file), m_variable_map(variable_map), m_sc(sc) {
143142
source_file.getParentModule()->setDebugClient(this);
144143

145144
if (!m_sc.target_sp)
@@ -177,11 +176,15 @@ void LLDBNameLookup::RegisterTypeAliases(
177176

178177
/// A name lookup class for debugger expr mode.
179178
class LLDBExprNameLookup : public LLDBNameLookup {
179+
const SwiftASTContextForExpressions *m_this_context;
180+
180181
public:
181182
LLDBExprNameLookup(swift::SourceFile &source_file,
182183
SwiftExpressionParser::SILVariableMap &variable_map,
183-
SymbolContext &sc, ExecutionContextScope &exe_scope)
184-
: LLDBNameLookup(source_file, variable_map, sc, exe_scope) {}
184+
SymbolContext &sc, ExecutionContextScope &exe_scope,
185+
const SwiftASTContextForExpressions *this_context)
186+
: LLDBNameLookup(source_file, variable_map, sc, exe_scope),
187+
m_this_context(this_context) {}
185188

186189
bool shouldGlobalize(swift::Identifier Name, swift::DeclKind Kind) override {
187190
// Extensions have to be globalized, there's no way to mark them
@@ -195,7 +198,7 @@ class LLDBExprNameLookup : public LLDBNameLookup {
195198
return true;
196199

197200
if (Name.str().starts_with("$")) {
198-
LLDB_LOG(m_log,
201+
LLDB_LOG(GetLog(LLDBLog::Expressions),
199202
"[LLDBExprNameLookup::shouldGlobalize] Returning true to "
200203
"globalizing {0}",
201204
Name.str());
@@ -223,7 +226,7 @@ class LLDBExprNameLookup : public LLDBNameLookup {
223226
static unsigned counter = 0;
224227
unsigned count = counter++;
225228

226-
LLDB_LOG(m_log,
229+
LLDB_LOG(GetLog(LLDBLog::Expressions),
227230
"[LLDBExprNameLookup::lookupOverrides({0})] Searching for \"{1}\"",
228231
count, Name.getIdentifier().get());
229232

@@ -234,6 +237,8 @@ class LLDBExprNameLookup : public LLDBNameLookup {
234237
swift::SourceLoc Loc, bool IsTypeLookup,
235238
ResultVector &RV) override {
236239
LLDB_SCOPED_TIMER();
240+
assert(SwiftASTContext::GetSwiftASTContext(&DC->getASTContext()) ==
241+
m_this_context);
237242
static unsigned counter = 0;
238243
unsigned count = counter++;
239244

@@ -242,7 +247,7 @@ class LLDBExprNameLookup : public LLDBNameLookup {
242247
return false;
243248

244249
LLDB_LOG(
245-
m_log,
250+
GetLog(LLDBLog::Expressions),
246251
"[LLDBExprNameLookup::lookupAdditions ({0})] Searching for \"{1}\"",
247252
count, NameStr);
248253

@@ -290,9 +295,10 @@ class LLDBExprNameLookup : public LLDBNameLookup {
290295
persistent_results);
291296

292297
for (CompilerDecl & decl : persistent_results) {
293-
if (decl.GetTypeSystem() !=
294-
SwiftASTContext::GetSwiftASTContext(&DC->getASTContext())) {
295-
LLDB_LOG(m_log, "ignoring persistent result from other context");
298+
if (decl.GetTypeSystem() != m_this_context) {
299+
LLDB_LOG(GetLog(LLDBLog::Expressions),
300+
"Ignoring persistent result from other context: {0}",
301+
NameStr);
296302
continue;
297303
}
298304
auto *value_decl =
@@ -368,11 +374,15 @@ class LLDBExprNameLookup : public LLDBNameLookup {
368374

369375
/// A name lookup class for REPL and Playground mode.
370376
class LLDBREPLNameLookup : public LLDBNameLookup {
377+
const SwiftASTContextForExpressions *m_this_context;
378+
371379
public:
372380
LLDBREPLNameLookup(swift::SourceFile &source_file,
373381
SwiftExpressionParser::SILVariableMap &variable_map,
374-
SymbolContext &sc, ExecutionContextScope &exe_scope)
375-
: LLDBNameLookup(source_file, variable_map, sc, exe_scope) {}
382+
SymbolContext &sc, ExecutionContextScope &exe_scope,
383+
const SwiftASTContextForExpressions *this_context)
384+
: LLDBNameLookup(source_file, variable_map, sc, exe_scope),
385+
m_this_context(this_context) {}
376386

377387
bool shouldGlobalize(swift::Identifier Name, swift::DeclKind kind) override {
378388
return false;
@@ -390,6 +400,9 @@ class LLDBREPLNameLookup : public LLDBNameLookup {
390400
swift::SourceLoc Loc, bool IsTypeLookup,
391401
ResultVector &RV) override {
392402
LLDB_SCOPED_TIMER();
403+
404+
assert(SwiftASTContext::GetSwiftASTContext(&DC->getASTContext()) ==
405+
m_this_context);
393406
static unsigned counter = 0;
394407
unsigned count = counter++;
395408

@@ -398,7 +411,7 @@ class LLDBREPLNameLookup : public LLDBNameLookup {
398411
return false;
399412

400413
LLDB_LOG(
401-
m_log,
414+
GetLog(LLDBLog::Expressions),
402415
"[LLDBREPLNameLookup::lookupAdditions ({0})] Searching for \"{1}\"",
403416
count, NameStr);
404417

@@ -420,6 +433,12 @@ class LLDBREPLNameLookup : public LLDBNameLookup {
420433

421434
// Append the persistent decls that we found to the result vector.
422435
for (auto result : persistent_decl_results) {
436+
if (result.GetTypeSystem() != m_this_context) {
437+
LLDB_LOG(GetLog(LLDBLog::Expressions),
438+
"Ignoring persistent result from other context: {0}", NameStr);
439+
continue;
440+
}
441+
423442
// No import required.
424443
auto *result_decl =
425444
static_cast<swift::ValueDecl *>(result.GetOpaqueDecl());
@@ -1375,11 +1394,11 @@ SwiftExpressionParser::ParseAndImport(
13751394

13761395
LLDBNameLookup *external_lookup;
13771396
if (m_options.GetPlaygroundTransformEnabled() || m_options.GetREPLEnabled()) {
1378-
external_lookup =
1379-
new LLDBREPLNameLookup(*source_file, variable_map, m_sc, *m_exe_scope);
1397+
external_lookup = new LLDBREPLNameLookup(*source_file, variable_map, m_sc,
1398+
*m_exe_scope, &m_swift_ast_ctx);
13801399
} else {
1381-
external_lookup =
1382-
new LLDBExprNameLookup(*source_file, variable_map, m_sc, *m_exe_scope);
1400+
external_lookup = new LLDBExprNameLookup(*source_file, variable_map, m_sc,
1401+
*m_exe_scope, &m_swift_ast_ctx);
13831402
}
13841403

13851404
// FIXME: This call is here just so that the we keep the
@@ -1758,8 +1777,15 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
17581777

17591778
// Signal that we want to retry the expression exactly once with a
17601779
// fresh SwiftASTContext.
1761-
if (retry)
1780+
if (retry) {
1781+
if (auto *persistent_state =
1782+
llvm::cast_or_null<SwiftPersistentExpressionState>(
1783+
m_sc.target_sp->GetPersistentExpressionStateForLanguage(
1784+
lldb::eLanguageTypeSwift)))
1785+
persistent_state->Clear();
1786+
17621787
return ParseResult::retry_fresh_context;
1788+
}
17631789

17641790
// Unrecoverable error.
17651791
return ParseResult::unrecoverable_error;
@@ -2023,6 +2049,11 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
20232049
return ParseResult::unrecoverable_error;
20242050
}
20252051

2052+
if (m_swift_ast_ctx.GetASTContext()->hadError()) {
2053+
DiagnoseSwiftASTContextError();
2054+
return ParseResult::unrecoverable_error;
2055+
}
2056+
20262057
{
20272058
std::lock_guard<std::recursive_mutex> global_context_locker(
20282059
IRExecutionUnit::GetLLVMGlobalContextMutex());

lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ class SwiftExpressionParser : public ExpressionParser {
212212
/// The container for the IR, to be JIT-compiled or interpreted.
213213
lldb::IRExecutionUnitSP m_execution_unit_sp;
214214
/// The AST context to build the expression into.
215+
/// A shared pointer of this is held by SwiftUserexpression.
215216
SwiftASTContextForExpressions &m_swift_ast_ctx;
216217
/// Used to manage the memory of a potential on-off context.
217218
//lldb::TypeSystemSP m_typesystem_sp;
@@ -254,7 +255,6 @@ class LLDBNameLookup : public swift::SILDebuggerClient {
254255
llvm::SmallVectorImpl<swift::TypeAliasDecl *> &type_aliases);
255256

256257
protected:
257-
Log *m_log;
258258
swift::SourceFile &m_source_file;
259259
SwiftExpressionParser::SILVariableMap &m_variable_map;
260260
SymbolContext m_sc;

lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class SwiftPersistentExpressionState : public PersistentExpressionState {
4848

4949
void CopyDeclsTo(SwiftDeclMap &target_map);
5050
static bool DeclsAreEquivalent(CompilerDecl lhs, CompilerDecl rhs);
51+
void Clear() { m_swift_decls.clear(); }
5152

5253
private:
5354
/// Each decl also stores the context it comes from.
@@ -102,6 +103,8 @@ class SwiftPersistentExpressionState : public PersistentExpressionState {
102103
const std::vector<CompilerDecl> &excluding_equivalents,
103104
std::vector<CompilerDecl> &matches);
104105

106+
void Clear() { m_swift_persistent_decls.Clear(); }
107+
105108
private:
106109
/// The counter used by GetNextResultName().
107110
uint32_t m_next_persistent_variable_id;

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,9 +1089,6 @@ class SwiftASTContextForExpressions : public SwiftASTContext {
10891089
/// These are the names of modules that we have loaded by hand into
10901090
/// the Contexts we make for parsing.
10911091
HandLoadedModuleSet m_hand_loaded_modules;
1092-
1093-
private:
1094-
std::unique_ptr<SwiftPersistentExpressionState> m_persistent_state_up;
10951092
};
10961093

10971094
} // namespace lldb_private
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
let comment = "Populate the persistent state with some fields"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
public func f() -> String { return "Hello from the Dylib!" }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Dylib
2+
f()
3+
let comment = "and back again"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
all: Dylib.framework
2+
3+
Dylib.framework: Dylib.swift
4+
"$(MAKE)" -f $(MAKEFILE_RULES) \
5+
FRAMEWORK=Dylib \
6+
DYLIB_SWIFT_SOURCES=Dylib.swift \
7+
DYLIB_NAME=Dylib \
8+
SWIFTFLAGS_EXTRAS="-Xcc -DNEW_OPTION_FROM_DYLIB=1" \
9+
MAKE_DSYM=YES
10+
11+
include ../Makefile.common
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// PlaygroundStub.swift
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
// -----------------------------------------------------------------------------
12+
13+
@_silgen_name ("playground_logger_initialize") func builtin_initialize();
14+
@_silgen_name ("GetOutput") func get_output() -> String;
15+
16+
builtin_initialize();
17+
18+
print(""); // Set breakpoint here
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// PlaygroundsRuntime.swift
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
// -----------------------------------------------------------------------------
12+
13+
// If you're modifying this file to add or modify function signatures, you
14+
// should be notifying the maintainer of PlaygroundLogger and also the
15+
// maintainer of lib/Sema/PlaygroundTransform.cpp.
16+
17+
var PlaygroundOutput = ""
18+
19+
struct SourceRange {
20+
let sl : Int
21+
let el : Int
22+
let sc : Int
23+
let ec : Int
24+
var text : String {
25+
return "[\(sl):\(sc)-\(el):\(ec)]"
26+
}
27+
}
28+
29+
struct ModuleFileIdentifier {
30+
let moduleId : Int
31+
let fileId : Int
32+
var text : String {
33+
return "[\(moduleId):\(fileId)]"
34+
}
35+
}
36+
37+
class LogRecord {
38+
let text : String
39+
40+
init(api : String, object : Any, name : String, id : Int, range : SourceRange, moduleFileId : ModuleFileIdentifier) {
41+
var object_description : String = ""
42+
print(object, terminator: "", to: &object_description)
43+
text = moduleFileId.text + " " + range.text + " " + api + "[" + name + "='" + object_description + "']"
44+
}
45+
init(api : String, object : Any, name : String, range : SourceRange, moduleFileId : ModuleFileIdentifier) {
46+
var object_description : String = ""
47+
print(object, terminator: "", to: &object_description)
48+
text = moduleFileId.text + " " + range.text + " " + api + "[" + name + "='" + object_description + "']"
49+
}
50+
init(api : String, object: Any, range : SourceRange, moduleFileId : ModuleFileIdentifier) {
51+
var object_description : String = ""
52+
print(object, terminator: "", to: &object_description)
53+
text = moduleFileId.text + " " + range.text + " " + api + "['" + object_description + "']"
54+
}
55+
init(api: String, range : SourceRange, moduleFileId : ModuleFileIdentifier) {
56+
text = moduleFileId.text + " " + range.text + " " + api
57+
}
58+
}
59+
60+
@_silgen_name ("playground_logger_initialize") public func builtin_initialize() {
61+
}
62+
63+
@_silgen_name ("playground_log_hidden") public func builtin_log_with_id<T>(_ object : T, _ name : String, _ id : Int, _ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) -> AnyObject? {
64+
let moduleFileId = ModuleFileIdentifier(moduleId:moduleId, fileId:fileId)
65+
return LogRecord(api:"__builtin_log", object:object, name:name, id:id, range : SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
66+
}
67+
68+
@_silgen_name ("playground_log_scope_entry") public func builtin_log_scope_entry(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) -> AnyObject? {
69+
let moduleFileId = ModuleFileIdentifier(moduleId:moduleId, fileId:fileId)
70+
return LogRecord(api:"__builtin_log_scope_entry", range : SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
71+
}
72+
73+
@_silgen_name ("playground_log_scope_exit") public func builtin_log_scope_exit(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) -> AnyObject? {
74+
let moduleFileId = ModuleFileIdentifier(moduleId:moduleId, fileId:fileId)
75+
return LogRecord(api:"__builtin_log_scope_exit", range : SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
76+
}
77+
78+
@_silgen_name ("playground_log_postprint") public func builtin_postPrint(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int, _ moduleId : Int, _ fileId : Int) -> AnyObject? {
79+
let moduleFileId = ModuleFileIdentifier(moduleId:moduleId, fileId:fileId)
80+
return LogRecord(api:"__builtin_postPrint", range : SourceRange(sl:sl, el:el, sc:sc, ec:ec), moduleFileId:moduleFileId)
81+
}
82+
83+
@_silgen_name ("DVTSendPlaygroundLogData") public func builtin_send_data(_ object:AnyObject?) {
84+
print((object as! LogRecord).text)
85+
PlaygroundOutput.append((object as! LogRecord).text)
86+
PlaygroundOutput.append("\n")
87+
}
88+
89+
@_silgen_name ("GetOutput") public func get_output() -> String {
90+
return PlaygroundOutput
91+
}
92+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import print_function
2+
import lldbsuite.test.lldbplaygroundrepl as repl
3+
from lldbsuite.test.lldbtest import *
4+
5+
class TestPlaygroundREPLImport(repl.PlaygroundREPLTest):
6+
7+
mydir = repl.PlaygroundREPLTest.compute_mydir(__file__)
8+
9+
def do_test(self):
10+
"""
11+
Test importing a library that adds new Clang options.
12+
"""
13+
self.expect('settings set target.swift-framework-search-paths "%s"' %
14+
self.getBuildDir())
15+
self.expect('settings set target.use-all-compiler-flags true')
16+
17+
log = self.getBuildArtifact('types.log')
18+
self.expect('log enable lldb types -f ' + log)
19+
result, playground_output = self.execute_code('BeforeImport.swift')
20+
self.assertIn("persistent", playground_output.GetSummary())
21+
result, playground_output = self.execute_code('Import.swift')
22+
self.assertIn("Hello from the Dylib", playground_output.GetSummary())
23+
self.assertIn("and back again", playground_output.GetSummary())
24+
25+
# Scan through the types log to make sure the SwiftASTContext was poisoned.
26+
self.filecheck('platform shell cat ""%s"' % log, __file__)
27+
# CHECK: New Swift image added{{.*}}Versions/A/Dylib{{.*}}ClangImporter needs to be reinitialized
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import Dylib
22
f()
3+
let comment = "and back again"

0 commit comments

Comments
 (0)