Skip to content

Commit e49a3ec

Browse files
Merge pull request #10174 from adrian-prantl/cherry-pick-next-lldb-Fix-use-after-free-in-Playgrounds
[Cherry-pick into next] [lldb] Fix use-after-free in Playgrounds
2 parents 3da4049 + cce1653 commit e49a3ec

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
@@ -139,8 +139,7 @@ LLDBNameLookup::LLDBNameLookup(
139139
SwiftExpressionParser::SILVariableMap &variable_map, SymbolContext &sc,
140140
ExecutionContextScope &exe_scope)
141141
: SILDebuggerClient(source_file.getASTContext()),
142-
m_log(GetLog(LLDBLog::Expressions)), m_source_file(source_file),
143-
m_variable_map(variable_map), m_sc(sc) {
142+
m_source_file(source_file), m_variable_map(variable_map), m_sc(sc) {
144143
source_file.getParentModule()->setDebugClient(this);
145144

146145
if (!m_sc.target_sp)
@@ -178,11 +177,15 @@ void LLDBNameLookup::RegisterTypeAliases(
178177

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

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

198201
if (Name.str().starts_with("$")) {
199-
LLDB_LOG(m_log,
202+
LLDB_LOG(GetLog(LLDBLog::Expressions),
200203
"[LLDBExprNameLookup::shouldGlobalize] Returning true to "
201204
"globalizing {0}",
202205
Name.str());
@@ -224,7 +227,7 @@ class LLDBExprNameLookup : public LLDBNameLookup {
224227
static unsigned counter = 0;
225228
unsigned count = counter++;
226229

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

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

@@ -243,7 +248,7 @@ class LLDBExprNameLookup : public LLDBNameLookup {
243248
return false;
244249

245250
LLDB_LOG(
246-
m_log,
251+
GetLog(LLDBLog::Expressions),
247252
"[LLDBExprNameLookup::lookupAdditions ({0})] Searching for \"{1}\"",
248253
count, NameStr);
249254

@@ -291,9 +296,10 @@ class LLDBExprNameLookup : public LLDBNameLookup {
291296
persistent_results);
292297

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

370376
/// A name lookup class for REPL and Playground mode.
371377
class LLDBREPLNameLookup : public LLDBNameLookup {
378+
const SwiftASTContextForExpressions *m_this_context;
379+
372380
public:
373381
LLDBREPLNameLookup(swift::SourceFile &source_file,
374382
SwiftExpressionParser::SILVariableMap &variable_map,
375-
SymbolContext &sc, ExecutionContextScope &exe_scope)
376-
: LLDBNameLookup(source_file, variable_map, sc, exe_scope) {}
383+
SymbolContext &sc, ExecutionContextScope &exe_scope,
384+
const SwiftASTContextForExpressions *this_context)
385+
: LLDBNameLookup(source_file, variable_map, sc, exe_scope),
386+
m_this_context(this_context) {}
377387

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

@@ -399,7 +412,7 @@ class LLDBREPLNameLookup : public LLDBNameLookup {
399412
return false;
400413

401414
LLDB_LOG(
402-
m_log,
415+
GetLog(LLDBLog::Expressions),
403416
"[LLDBREPLNameLookup::lookupAdditions ({0})] Searching for \"{1}\"",
404417
count, NameStr);
405418

@@ -421,6 +434,12 @@ class LLDBREPLNameLookup : public LLDBNameLookup {
421434

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

13811400
LLDBNameLookup *external_lookup;
13821401
if (m_options.GetPlaygroundTransformEnabled() || m_options.GetREPLEnabled()) {
1383-
external_lookup =
1384-
new LLDBREPLNameLookup(*source_file, variable_map, m_sc, *m_exe_scope);
1402+
external_lookup = new LLDBREPLNameLookup(*source_file, variable_map, m_sc,
1403+
*m_exe_scope, &m_swift_ast_ctx);
13851404
} else {
1386-
external_lookup =
1387-
new LLDBExprNameLookup(*source_file, variable_map, m_sc, *m_exe_scope);
1405+
external_lookup = new LLDBExprNameLookup(*source_file, variable_map, m_sc,
1406+
*m_exe_scope, &m_swift_ast_ctx);
13881407
}
13891408

13901409
// FIXME: This call is here just so that the we keep the
@@ -1769,8 +1788,15 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
17691788

17701789
// Signal that we want to retry the expression exactly once with a
17711790
// fresh SwiftASTContext.
1772-
if (retry)
1791+
if (retry) {
1792+
if (auto *persistent_state =
1793+
llvm::cast_or_null<SwiftPersistentExpressionState>(
1794+
m_sc.target_sp->GetPersistentExpressionStateForLanguage(
1795+
lldb::eLanguageTypeSwift)))
1796+
persistent_state->Clear();
1797+
17731798
return ParseResult::retry_fresh_context;
1799+
}
17741800

17751801
// Unrecoverable error.
17761802
return parse_result_failure;
@@ -2033,6 +2059,11 @@ SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager,
20332059
return parse_result_failure;
20342060
}
20352061

2062+
if (m_swift_ast_ctx.GetASTContext()->hadError()) {
2063+
DiagnoseSwiftASTContextError();
2064+
return ParseResult::unrecoverable_error;
2065+
}
2066+
20362067
{
20372068
std::lock_guard<std::recursive_mutex> global_context_locker(
20382069
IRExecutionUnit::GetLLVMGlobalContextMutex());

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ class SwiftExpressionParser : public ExpressionParser {
215215
/// The container for the IR, to be JIT-compiled or interpreted.
216216
lldb::IRExecutionUnitSP m_execution_unit_sp;
217217
/// The AST context to build the expression into.
218+
/// A shared pointer of this is held by SwiftUserexpression.
218219
SwiftASTContextForExpressions &m_swift_ast_ctx;
219220
/// Used to manage the memory of a potential on-off context.
220221
//lldb::TypeSystemSP m_typesystem_sp;
@@ -257,7 +258,6 @@ class LLDBNameLookup : public swift::SILDebuggerClient {
257258
llvm::SmallVectorImpl<swift::TypeAliasDecl *> &type_aliases);
258259

259260
protected:
260-
Log *m_log;
261261
swift::SourceFile &m_source_file;
262262
SwiftExpressionParser::SILVariableMap &m_variable_map;
263263
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
@@ -1104,9 +1104,6 @@ class SwiftASTContextForExpressions : public SwiftASTContext {
11041104
/// These are the names of modules that we have loaded by hand into
11051105
/// the Contexts we make for parsing.
11061106
HandLoadedModuleSet m_hand_loaded_modules;
1107-
1108-
private:
1109-
std::unique_ptr<SwiftPersistentExpressionState> m_persistent_state_up;
11101107
};
11111108

11121109
} // 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)