From 9bd603e3780b0a1448571909ec1ec955e835e2d1 Mon Sep 17 00:00:00 2001 From: rconnell9 Date: Fri, 8 Aug 2025 06:27:54 -0400 Subject: [PATCH] Frequent crashes in LLBuildProgressTracker while building swift-java on linux and swift 6.1.2 (#8998) Frequent crashes in LLBuildProgressTracker while building swift-java on linux and swift 6.1.2 > Thread 4 crashed: > > 0 0x00007f1559da359a swift_slowAlloc + 74 in [libswiftCore.so](http://libswiftcore.so/) > 1 [ra] 0x00007f1559da3877 swift_allocObject + 38 in [libswiftCore.so](http://libswiftcore.so/) > 2 [ra] 0x00007f1559b85571 _allocateStringStorage(codeUnitCapacity:) + 160 in [libswiftCore.so](http://libswiftcore.so/) > 3 [ra] 0x00007f1559d03452 _StringGuts.grow(_:) + 273 in [libswiftCore.so](http://libswiftcore.so/) > 4 [ra] 0x00007f1559bf7e88 specialized static String._fromUTF8Repairing(_:) + 999 in [libswiftCore.so](http://libswiftcore.so/) > 5 [ra] [inlined] [system] 0x000056315a96e7ef specialized String.init(decoding:as:) in swift-package at // > 6 [ra] [inlined] 0x000056315a96e7ef stringFromData(_:) in swift-package at /home/build-user/llbuild/products/llbuildSwift/Internals.swift:49:12 > 7 [ra] 0x000056315a96e7ef Command.name.getter + 78 in swift-package at /home/build-user/llbuild/products/llbuildSwift/BuildSystemBindings.swift:720:20 > 8 [ra] 0x00005631593a61a2 closure #1 in LLBuildProgressTracker.commandProcessFinished(_:process:result:) + 33 in swift-package at /home/build-user/swiftpm/Sources/Build/LLBuildProgressTracker.swift:347:65 > 9 [ra] [thunk] 0x00005631592f6989 thunk for @escaping @callee_guaranteed @Sendable () -> () + 24 in swift-package at // Command is associated with a handle (pointer) that may be reclaimed when this function finishes. Do not access command attributes asynchronously (cherry picked from commit 16452e1305d5f635cc714146201ca9753bcfea3f) --- Sources/Build/LLBuildProgressTracker.swift | 36 +++++++++++++--------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/Sources/Build/LLBuildProgressTracker.swift b/Sources/Build/LLBuildProgressTracker.swift index 8b0c8c3571b..c6fa8d330de 100644 --- a/Sources/Build/LLBuildProgressTracker.swift +++ b/Sources/Build/LLBuildProgressTracker.swift @@ -277,6 +277,9 @@ final class LLBuildProgressTracker: LLBuildBuildSystemDelegate, SwiftCompilerOut guard command.shouldShowStatus else { return } guard !self.swiftParsers.keys.contains(command.name) else { return } + let commandName = command.name + let commandDescription = command.description + self.queue.async { if result == .cancelled { self.cancelled = true @@ -286,8 +289,8 @@ final class LLBuildProgressTracker: LLBuildBuildSystemDelegate, SwiftCompilerOut self.delegate?.buildSystem(self.buildSystem, didFinishCommand: BuildSystemCommand(command)) if !self.logLevel.isVerbose { - let targetName = self.swiftParsers[command.name]?.targetName - self.taskTracker.commandFinished(command, result: result, targetName: targetName) + let targetName = self.swiftParsers[commandName]?.targetName + self.taskTracker.commandFinished(commandDescription, result: result, targetName: targetName) self.updateProgress() } } @@ -343,12 +346,15 @@ final class LLBuildProgressTracker: LLBuildBuildSystemDelegate, SwiftCompilerOut // FIXME: This should really happen at the command-level and is just a stopgap measure. let shouldFilterOutput = !self.logLevel.isVerbose && command.verboseDescription.hasPrefix("codesign ") && result .result != .failed + + let commandName = command.name + self.queue.async { - if let buffer = self.nonSwiftMessageBuffers[command.name], !shouldFilterOutput { + if let buffer = self.nonSwiftMessageBuffers[commandName], !shouldFilterOutput { self.progressAnimation.clear() self.outputStream.send(buffer) self.outputStream.flush() - self.nonSwiftMessageBuffers[command.name] = nil + self.nonSwiftMessageBuffers[commandName] = nil } } @@ -360,13 +366,13 @@ final class LLBuildProgressTracker: LLBuildBuildSystemDelegate, SwiftCompilerOut // The command failed, so we queue up an asynchronous task to see if we have any error messages from the // target to provide advice about. self.queue.async { - guard let target = self.swiftParsers[command.name]?.targetName else { return } + guard let target = self.swiftParsers[commandName]?.targetName else { return } guard let errorMessages = self.errorMessagesByTarget[target] else { return } for errorMessage in errorMessages { // Emit any advice that's provided for each error message. if let adviceMessage = self.buildExecutionContext.buildErrorAdviceProvider?.provideBuildErrorAdvice( for: target, - command: command.name, + command: commandName, message: errorMessage ) { self.outputStream.send("note: \(adviceMessage)\n") @@ -530,8 +536,8 @@ private struct CommandTaskTracker { } } - mutating func commandFinished(_ command: SPMLLBuild.Command, result: CommandResult, targetName: String?) { - let progressTextValue = self.progressText(of: command, targetName: targetName) + mutating func commandFinished(_ commandDescription: String, result: CommandResult, targetName: String?) { + let progressTextValue = self.progressText(of: commandDescription, targetName: targetName) self.onTaskProgressUpdateText?(progressTextValue, targetName) self.latestFinishedText = progressTextValue @@ -558,14 +564,14 @@ private struct CommandTaskTracker { } } - private func progressText(of command: SPMLLBuild.Command, targetName: String?) -> String { + private func progressText(of commandDescription: String, targetName: String?) -> String { // Transforms descriptions like "Linking ./.build/x86_64-apple-macosx/debug/foo" into "Linking foo". - if let firstSpaceIndex = command.description.firstIndex(of: " "), - let lastDirectorySeparatorIndex = command.description.lastIndex(of: "/") + if let firstSpaceIndex = commandDescription.firstIndex(of: " "), + let lastDirectorySeparatorIndex = commandDescription.lastIndex(of: "/") { - let action = command.description[..