From 0ecee7dcca5c9ee078d3a09a22623fe1f91b946d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 14 Dec 2025 19:42:57 +0530 Subject: [PATCH] macOS: Workaround for regression in Tahoe 26.2 that breaks --detach Fixes #9288 --- docs/changelog.rst | 3 +++ kitty/launcher/main.c | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index c65560734..3ee369a55 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -192,6 +192,9 @@ Detailed list of changes - Fix :opt:`tab_bar_min_tabs` not respecting :opt:`tab_bar_filter` (:iss:`9278`) +- macOS: Workaround for regression in Tahoe 26.2 that breaks :option:`--detach` + (:iss:`9288`) + 0.44.0 [2025-11-03] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/launcher/main.c b/kitty/launcher/main.c index 8a5d54a28..b892215f6 100644 --- a/kitty/launcher/main.c +++ b/kitty/launcher/main.c @@ -388,7 +388,16 @@ handle_fast_commandline(CLISpec *cli_spec, const char *instance_group_prefix) { exit(0); } opts.session = get_string_cli_val(cli_spec, "session"); - if (get_bool_cli_val(cli_spec, "detach")) { +#ifdef __APPLE__ + char pid_str[32]; + snprintf(pid_str, sizeof(pid_str), "%d", getpid()); + const char *ekfd = getenv("KITTY_EXEC_FOR_DETACH"); + bool is_exec_for_detach = ekfd && strcmp(getenv("KITTY_EXEC_FOR_DETACH"), pid_str) == 0; + if (is_exec_for_detach) unsetenv("KITTY_EXEC_FOR_DETACH"); +#else + bool is_exec_for_detach = false; +#endif + if (get_bool_cli_val(cli_spec, "detach") && !is_exec_for_detach) { const char *detached_log = get_string_cli_val(cli_spec, "detached_log"); if (being_tested) { printf("detach: true\n"); @@ -419,6 +428,18 @@ handle_fast_commandline(CLISpec *cli_spec, const char *instance_group_prefix) { errno = 0; while (close(fds[0]) != 0 && errno == EINTR); setsid(); errno = 0; while (close(fds[1]) != 0 && errno == EINTR); +#ifdef __APPLE__ + // fork() without exec() is unsafe on macOS. It used to work since + // in this case we havent yet loaded any major Cocoa libraries but + // in Tahoe 26.2 Apple broke that as well. So now just exec() on --detach + snprintf(pid_str, sizeof(pid_str), "%d", getpid()); + setenv("KITTY_EXEC_FOR_DETACH", pid_str, 1); + char exe_path[PATH_MAX] = {0}; + read_exe_path(exe_path, PATH_MAX); + execv(exe_path, cli_spec->original_argv); + fprintf(stderr, "Failed to execv() for --detach with exe_path: %s\n", exe_path); + exit(1); +#endif } } unsetenv("KITTY_SI_DATA");