From 4c15da9dea9db3bfda27e2ae63f7386050e96c39 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Thu, 4 Dec 2025 10:42:45 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Prevent=20crashing=20with=20Real?= =?UTF-8?q?Command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This addresses some potential crash issues with RealCommand. The PHPInstallation health check has been updated to accommodate the potential error strings, namely: - PHPMON_COMMAND_UNCAUGHT_SIGNAL - PHPMON_FILE_HANDLE_READ_FAILURE --- phpmon/Common/Command/RealCommand.swift | 24 ++++++++++++++++++++++-- phpmon/Common/PHP/PhpInstallation.swift | 14 +++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/phpmon/Common/Command/RealCommand.swift b/phpmon/Common/Command/RealCommand.swift index af27e7ac..5d8d90e9 100644 --- a/phpmon/Common/Command/RealCommand.swift +++ b/phpmon/Common/Command/RealCommand.swift @@ -15,6 +15,8 @@ public class RealCommand: CommandProtocol { withStandardError: Bool ) -> String { let task = Process() + var output = "" + task.launchPath = path task.arguments = arguments @@ -26,10 +28,28 @@ public class RealCommand: CommandProtocol { } task.launch() + task.waitUntilExit() - let data = pipe.fileHandleForReading.readDataToEndOfFile() - let output: String = String.init(data: data, encoding: String.Encoding.utf8)! + defer { + try? pipe.fileHandleForReading.close() + } + // Handle termination + if task.terminationReason == .uncaughtSignal { + Log.err("The command `\(path) w/ args: \(arguments)` likely crashed. Returning UNCAUGHT_SIGNAL.") + return "PHPMON_COMMAND_UNCAUGHT_SIGNAL" + } + + // Try reading from file handle and close it + if let data = try? pipe.fileHandleForReading.readToEnd() { + if let string = String(data: data, encoding: .utf8) { + output = string + } else { + return "PHPMON_FILE_HANDLE_READ_FAILURE" + } + } + + // Trim newline output if necessary if trimNewlines { return output.components(separatedBy: .newlines) .filter({ !$0.isEmpty }) diff --git a/phpmon/Common/PHP/PhpInstallation.swift b/phpmon/Common/PHP/PhpInstallation.swift index 7ba8b75d..3b85504c 100644 --- a/phpmon/Common/PHP/PhpInstallation.swift +++ b/phpmon/Common/PHP/PhpInstallation.swift @@ -94,11 +94,23 @@ class PhpInstallation { withStandardError: true ).trimmingCharacters(in: .whitespacesAndNewlines) + // The PHP executable did not return any output + if testCommand.isEmpty || testCommand.contains("HANDLE_READ_FAILURE") { + Log.err("No output. PHP \(self.versionNumber.short) is not healthy!") + self.isHealthy = false + } + + // The PHP executable crashed with an uncaught signal when we tried to run this + if testCommand.contains("UNCAUGHT_SIGNAL") { + Log.err("Uncaught signal, PHP \(self.versionNumber.short) is not healthy!") + self.isHealthy = false + } + // If the "dyld: Library not loaded" issue pops up, we have an unhealthy PHP installation // and we will need to reinstall this version of PHP via Homebrew. if testCommand.contains("Library not loaded") && testCommand.contains("dyld") { + Log.err("dyld error, PHP \(self.versionNumber.short) is not healthy!") self.isHealthy = false - Log.err("The PHP installation of \(self.versionNumber.short) is not healthy!") } } }