os_log crashing in MacOS 14 Sonoma

minimum is to create an os_log once in the parent, then, after fork, use an existing os_log instance or create a new one.

Here's my reproduction sample.

It looks like an OS bug, So what is the workaround till its solved and releases.



#include <os/log.h>
#include <stdio.h>
#include <errno.h>

#define USE_SWIFT_LOGGER 0  // set to 1 to use Logger() instead of os_log()
#define USE_SHARED_LOG 0    // set to 1 to use a shared os_log instance instead of allocating one for each os_log() call

#if USE_SWIFT_LOGGER
    // log messages using Swift's Logger class instead of calling os_log_... directly
    #include "forktest-Swift.h"
    #define LOG(msg) log_using_logger([NSString stringWithUTF8String:msg])
    const char * logMethod = "Swift's Logger";
#elif USE_SHARED_LOG
    // use a shared os_log instance for all log messages
    static os_log_t log = os_log_create("com.ivanti.forktest", "foo");
    #define LOG(msg) os_log_debug(log, msg)
    const char * logMethod = "shared log";
#else
    // create a new os_log instance for each log message
    #define LOG(msg) os_log_debug(os_log_create("com.ivanti.forktest", "foo"), msg)
    const char * logMethod = "new log instance for each message";
#endif

static void forkTest()
{
    int pid = fork();
    if (pid < 0)
    {
        fprintf(stderr, "fork failed: %s\n", strerror(errno));
        exit(1);
    }
    else if (pid == 0)
    {
        printf("in child process...\n");
        LOG("in child process...");
        printf("child process done\n");
    }
    else
    {
        printf("child process pid: %d\n", pid);
    }
}

int main(int arc, const char ** argv)
{
    printf("Log method: %s\n", logMethod);
    LOG("entering main...");
    forkTest();
    LOG("leaving main...");
    return 0;
}

Replies

It is working as expected in macOS version < 14.

It is working as expected in macOS version &lt; 14.

You are absolutely free to file a bug about this binary compatibility regression (and if you do, please post the bug number) but…

Your test is on very shaky ground.

There are very few APIs that are safe to use between a fork and an exec*. Given the relationship between fork and pthreads, the only APIs that I’d use here are the async signal safe ones. See the list in the sigaction man page. Notably, the system log APIs are not on that list.

You can learn more about this overall issue in this thread.

IMO, it’s best to avoid the fork without exec* environment entirely by adopting posix_spawn.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This was already filed as FB13268441 (including the above sample).

Add a Comment