Skip to content

Commit d1a00c2

Browse files
[Swift] Add crash reproducer support (#686)
Add support for swift crash reproducer so a crash reproducer is created if supported when a swift compiler crash happened.
1 parent a2443f7 commit d1a00c2

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

Sources/SWBCore/LibSwiftDriver/PlannedBuild.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,16 @@ extension LibSwiftDriver {
529529
}
530530
}
531531

532+
public func getCrashReproducerCommand(for job: PlannedSwiftDriverJob, output dir: Path) async throws -> [String]? {
533+
try await dispatchQueue.sync {
534+
let driverJob = try self.driverJob(for: job)
535+
guard let reproJob = self.jobExecutionDelegate?.getReproducerJob(job: driverJob, output: try VirtualPath(path: dir.str)) else {
536+
return nil
537+
}
538+
return try self.argsResolver.resolveArgumentList(for: reproJob, useResponseFiles: .heuristic)
539+
}
540+
}
541+
532542
public func getDiscoveredJobsAfterFinishing(job: PlannedSwiftDriverJob) throws -> [PlannedSwiftDriverJob] {
533543

534544
dispatchQueue.blocking_sync {

Sources/SWBTaskExecution/TaskActions/SwiftDriverJobTaskAction.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ public final class SwiftDriverJobTaskAction: TaskAction, BuildValueValidatingTas
420420
private var pid = llbuild_pid_t.invalid
421421

422422
var executionError: String?
423+
var wasSignaled: Bool = false
423424
private var processStarted = false
424425
private var _commandResult: CommandResult?
425426
var commandResult: CommandResult? {
@@ -469,10 +470,15 @@ public final class SwiftDriverJobTaskAction: TaskAction, BuildValueValidatingTas
469470
}
470471

471472
func processFinished(result: CommandExtendedResult) {
473+
if wasSignaled {
474+
// If the process was already signaled, this might be in a reproducer creation. No need to update finish status.
475+
return
476+
}
472477
guard let status = Processes.ExitStatus.init(rawValue: result.exitStatus) else {
473478
// nil means the job is stopped or continued. It should not call finished.
474479
return
475480
}
481+
wasSignaled = status.wasSignaled
476482
// This may be updated by commandStarted in the case of certain failures,
477483
// so only update the exit status in output delegate if it is nil.
478484
if outputDelegate.result == nil {
@@ -526,6 +532,21 @@ public final class SwiftDriverJobTaskAction: TaskAction, BuildValueValidatingTas
526532

527533
try await spawn(commandLine: options.commandLine, environment: environment, workingDirectory: task.workingDirectory, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: delegate)
528534

535+
// Generate crash reproducoer.
536+
if delegate.wasSignaled {
537+
// The output directory for crash reproducer is:
538+
// * Specified by environment
539+
// * Primary output path directory
540+
// * Temp directory
541+
let reproDir = environment["SWIFT_CRASH_DIAGNOSTICS_DIR"].map(Path.init) ?? driverJob.driverJob.outputs.first?.dirname
542+
try await withTemporaryDirectory(dir: reproDir, prefix: "swift-crash-reproducer", removeTreeOnDeinit: false) { dir in
543+
if let reproCommand = try await plannedBuild?.getCrashReproducerCommand(for: driverJob, output: dir) {
544+
try await spawn(commandLine: reproCommand, environment: environment, workingDirectory: task.workingDirectory, dynamicExecutionDelegate: dynamicExecutionDelegate, clientDelegate: clientDelegate, processDelegate: delegate)
545+
outputDelegate.note("Crash reproducer created in \(dir.str)")
546+
}
547+
}
548+
}
549+
529550
if let error = delegate.executionError {
530551
outputDelegate.error(error)
531552
return .failed

0 commit comments

Comments
 (0)