Repository: SerenityOS/serenity
File: Kernel/Syscalls/posix_spawn.cpp (C++)

Code before:
        setup_description(1);
        setup_description(2);

        return {};
    }));

    // Copy protected data
    // TODO: we are probably over-copying here
    with_protected_data([&](auto& my_protected_data) {
        child->with_mutable_protected_data([&](auto& child_protected_data) {
            child_protected_data.promises = my_protected_data.promises;
            child_protected_data.execpromises = my_protected_data.execpromises;
            child_protected_data.has_promises = my_protected_data.has_promises;
            child_protected_data.has_execpromises = my_protected_data.has_execpromises;
            child_protected_data.credentials = my_protected_data.credentials;
            child_protected_data.umask = my_protected_data.umask;
            child_protected_data.dumpable = my_protected_data.dumpable;
            child_protected_data.process_group = my_protected_data.process_group;
            // NOTE: Propagate jailed_until_exit property to child processes.
            // The jailed_until_exec property is also propagated, but will be
            // set to false once the child process is calling the execve syscall.
            if (my_protected_data.jailed_until_exit.was_set())
                child_protected_data.jailed_until_exit.set();
            child_protected_data.jailed_until_exec = my_protected_data.jailed_until_exec;
        });
    });

    dbgln_if(FORK_DEBUG, "posix_spawn: child={}", child);

    // A child created via fork(2) inherits a copy of its parent's signal mask
    child_first_thread->update_signal_mask(Thread::current()->signal_mask());

    // A child process created via fork(2) inherits a copy of its parent's alternate signal stack settings.
    child_first_thread->m_alternative_signal_stack = Thread::current()->m_alternative_signal_stack;

    thread_finalizer_guard.disarm(); // TODO: this probably isnt in the right place?

    m_scoped_process_list.with([&](auto& list_ptr) {
        if (list_ptr) {
            child->m_scoped_process_list.with([&](auto& child_list_ptr) {
                child_list_ptr = list_ptr;
            });
            list_ptr->attach(*child);
        }
    });

    Thread* new_main_thread = nullptr;
    InterruptsState previous_interrupts_state = InterruptsState::Enabled;
    TRY(child->exec(move(path), move(arguments), move(environment), new_main_thread, previous_interrupts_state));

    Process::register_new(*child);

Review comment (suggestion):
The process attributes should be updated as if fork and exec* where used: <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn.html>
> All process attributes, other than those influenced by the attributes set in the object referenced by attrp as specified above or by the file descriptor manipulations specified in file_actions, shall appear in the new process image as though [fork()](https://pubs.opengroup.org/onlinepubs/9799919799/functions/fork.html) had been called to create a child process and then a member of the [exec](https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html) family of functions had been called by the child process to execute the new process image.

`do_exec` seems to already set most of the protected data correctly, so I think you can remove most of this code here.
Only the `umask` and `process_group` aren't set in `do_exec`, so you need to copy them manually here.

Code after:
    // Copy protected data which isn't set by do_exec().
    child->with_mutable_protected_data([&](auto& child_protected_data) {
        with_protected_data([&](auto const& parent_protected_data) {
            child_protected_data.umask = parent_protected_data.umask;
            child_protected_data.process_group = parent_protected_data.process_group;
            child_protected_data.credentials = parent_protected_data.credentials;
        });
    });

    dbgln_if(FORK_DEBUG, "posix_spawn: child={}", child);

    // A child created via posix_spawn inherits a copy of its parent's signal mask
    child_first_thread->update_signal_mask(Thread::current()->signal_mask());

    m_scoped_process_list.with([&](auto const& list_ptr) {
        if (list_ptr) {
            child->m_scoped_process_list.with([&](auto& child_list_ptr) {
                child_list_ptr = list_ptr;
            });
            list_ptr->attach(*child);
        }
    });

    Thread* new_main_thread = nullptr;
    InterruptsState previous_interrupts_state = InterruptsState::Enabled;
    TRY(child->exec(move(path), move(arguments), move(environment), new_main_thread, previous_interrupts_state));
    thread_finalizer_guard.disarm();

    Process::register_new(*child);

    // NOTE: All user processes have a leaked ref on them. It's balanced by Thread::WaitBlockerSet::finalize().
    child->ref();

    PerformanceManager::add_process_created_event(*child);

    SpinlockLocker lock(g_scheduler_lock);
    new_main_thread->set_affinity(Thread::current()->affinity());
    new_main_thread->set_state(Thread::State::Runnable);

    return child->pid().value();
}
}