Avoid deadlocks after fork#303
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
bcb913a to
2a70190
Compare
License Check Results🚀 The license check job ran with the Bazel command: bazel run --lockfile_mode=error //:license-checkStatus: Click to expand output |
|
The created documentation from the pull request is available at: docu-html |
2a70190 to
9cc08d6
Compare
9cc08d6 to
67c0d0f
Compare
67c0d0f to
9c28979
Compare
| } | ||
|
|
||
| if (-1 == chdir(dirname(strncpy(path_copy, config.executable_path_.c_str(), string_size)))) | ||
| if (config->scheduling_priority_ < sched_get_priority_min(config->scheduling_policy_)) |
There was a problem hiding this comment.
Do you already want to move this to score/launch_manager/src/daemon/src/configuration/details/flatbuffer_type_converters.cpp?
| } | ||
|
|
||
| void changeCurrentWorkingDirectory(const score::lcm::internal::osal::OsalConfig& config) | ||
| // TODO: Move this into the config loader |
There was a problem hiding this comment.
I think only the scheduling priority range can be checked during config loading.
The executable may not be accessible yet at that time, in case the filesystem where the executable resides is only mounted later. So I think this access check has to be done at the time when we want to start the process.
There was a problem hiding this comment.
For the executable we could not check in advance and just detect it when execve fails
| if (config.comms_type_ != osal::CommsType::kLaunchManager) | ||
| { | ||
| result = setpgid(0, getpid()); | ||
| SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(result == 0, std::strerror(errno)); |
There was a problem hiding this comment.
I think the strategy to use asserts here is now conflicting with this #299
where asserts actually log to std::cerr which I guess is not safe to call btw. fork() and execve() either. Also the heap allocation from std::ostringstream is probably then a problem.
Do you have any suggestion how to resolve this?
There was a problem hiding this comment.
We could allocate a fixed buffer for the assertion handler and call write directly, bypassing std::cerr? write is async signal safe.
There was a problem hiding this comment.
It sounds like a good solution to me. What do you think @paulquiring ?
There was a problem hiding this comment.
We need something like this as assertion handler.
void my_signal_handler(int sig) {
char buffer[128];
// Format your string (snprintf is generally safe in practice though technically not guaranteed)
int len = snprintf(buffer, sizeof(buffer), "Caught signal %d\n", sig);
// write to stdout (file descriptor 1) is async-signal-safe
write(STDOUT_FILENO, buffer, len);
}This ensures that security properties are not accidentally left unset.
e249b48 to
4121230
Compare
Fork only copies the current thread, so from that point on we could deadlock if we access anything that was locked by another thread at the time of the fork.
As such we should play it safe and use only basic functions. This means assertions rather than logs for fatal errors, and no logging at all on the happy path.