Skip to content

Commit 288ae78

Browse files
committed
[Serialized diagnostics] Avoid generating filenames that break the reader
The serialized diagnostics reader has one very specific limitation it places on filenames: they must not end in `/`, because that makes them look like a directory. This is not documented, and the diagnostics reader will unceremoniously crash when trying to read such a file. While the reader should be fixed to at least fail gracefully in such cases, Swift also shouldn't generate such filenames. Right now, they can be generated when referencing an entity named `/` that is synthesized or comes from a module. When we encounter such file names, append `_operator` to avoid the problem. Fixes rdar://118217560.
1 parent 556c503 commit 288ae78

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

lib/Frontend/SerializedDiagnosticConsumer.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,17 @@ namespace serialized_diagnostics {
225225
} // namespace serialized_diagnostics
226226
} // namespace swift
227227

228+
/// Sanitize a filename for the purposes of the serialized diagnostics reader.
229+
static StringRef sanitizeFilename(
230+
StringRef filename, SmallString<32> &scratch) {
231+
if (!filename.endswith("/") && !filename.endswith("\\"))
232+
return filename;
233+
234+
scratch = filename;
235+
scratch += "_operator";
236+
return scratch;
237+
}
238+
228239
unsigned SerializedDiagnosticConsumer::getEmitFile(
229240
SourceManager &SM, StringRef Filename, unsigned bufferID
230241
) {
@@ -248,9 +259,14 @@ unsigned SerializedDiagnosticConsumer::getEmitFile(
248259
Record.push_back(entry);
249260
Record.push_back(0); // For legacy.
250261
Record.push_back(0); // For legacy.
251-
Record.push_back(Filename.size());
262+
263+
// Sanitize the filename enough that the serialized diagnostics reader won't
264+
// reject it.
265+
SmallString<32> filenameScratch;
266+
auto sanitizedFilename = sanitizeFilename(Filename, filenameScratch);
267+
Record.push_back(sanitizedFilename.size());
252268
State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME),
253-
Record, Filename.data());
269+
Record, sanitizedFilename.data());
254270

255271
// If the buffer contains code that was synthesized by the compiler,
256272
// emit the contents of the buffer.

test/diagnostics/Inputs/slash.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
public func /(lhs: String, b: Int) -> Bool { false }
2+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t/SlashA.swiftmodule %S/Inputs/slash.swift
3+
// RUN: %target-swift-frontend -emit-module -o %t/SlashB.swiftmodule %S/Inputs/slash.swift
4+
// RUN: not %target-swift-frontend -typecheck -I %t -serialize-diagnostics-path %t/serialized.dia %s
5+
// RUN: c-index-test -read-diagnostics %t/serialized.dia > %t/serialized.txt 2>&1
6+
// RUN: %FileCheck %s -check-prefix CHECK-DIA < %t/serialized.txt
7+
8+
import SlashA
9+
import SlashB
10+
11+
func test(a: String, b: Int) -> Bool {
12+
// CHECK-DIA: [[@LINE+3]]:5: error: ambiguous use of operator '/'
13+
// CHECK-DIA: SlashA./_operator
14+
// CHECK-DIA: SlashB./_operator
15+
a / b
16+
}

0 commit comments

Comments
 (0)