mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
fix(launchd): preserve tracked children in nested job managers
Signed-off-by: lucannez64 <[email protected]>
This commit is contained in:
1 parent
4476761f02
commit
c38f5c29e0
3 files changed
+101
-1
No files matched your search
@@ -37,6 +37,7 @@ jobs:
|
||||
- run: python -m unittest discover -s tests -p 'test_exec_guest.py'
|
||||
- run: python -m unittest discover -s tests -p 'test_close_league_client_in_game.py'
|
||||
- run: python -m unittest discover -s tests -p 'test_recover_stale_client.py'
|
||||
- run: python -m unittest discover -s tests -p 'test_launchd_orphan_reaping.py'
|
||||
- run: python -m unittest discover -s tests -p 'test_clean_stale_helpers.py'
|
||||
- run: python -m unittest discover -s tests -p 'test_hide_league_client_in_game.py'
|
||||
- run: python -m unittest discover -s tests -p 'test_client_in_game_tricks.py'
|
||||
@@ -11442,7 +11442,7 @@ index a68739ff..5c8eb836 100644
|
||||
+ if (proc.pbsi_status != SZOMB) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (jobmgr_find_by_pid(root_jobmgr, pid, false) != NULL) {
|
||||
+ if (jobmgr_find_by_pid_deep(root_jobmgr, pid, true) != NULL) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
"""Run the patched launchd reaper against tracked and orphaned child fixtures."""
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import unittest
|
||||
|
||||
import test_runtime_compatibility as sources
|
||||
|
||||
|
||||
@unittest.skipUnless(shutil.which('cc'), 'C compiler required')
|
||||
class OrphanReapingTests(unittest.TestCase):
|
||||
run_c = sources.CompatibilityChecks.run_c
|
||||
|
||||
def test_only_untracked_zombie_children_are_reaped(self):
|
||||
patch = (Path(__file__).resolve().parents[1] / 'patches/darling.patch').read_text()
|
||||
section = patch.split('diff --git a/src/launchd/src/core.c ', 1)[1]
|
||||
added = '\n'.join(line[1:] for line in section.splitlines()
|
||||
if line.startswith('+') and not line.startswith('+++'))
|
||||
reaper = sources.function(added.replace('void\njobmgr_reap_orphaned_children',
|
||||
'void jobmgr_reap_orphaned_children'),
|
||||
'jobmgr_reap_orphaned_children')
|
||||
self.run_c(r'''
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
typedef int pid_t;
|
||||
typedef struct { int unused; } DIR;
|
||||
struct dirent { char d_name[16]; };
|
||||
struct proc_bsdshortinfo { int pbsi_ppid, pbsi_status; };
|
||||
struct job { int pid; bool anonymous; };
|
||||
struct manager {
|
||||
struct job *job;
|
||||
struct manager *child;
|
||||
};
|
||||
typedef struct manager *jobmgr_t;
|
||||
typedef struct job *job_t;
|
||||
#define SZOMB 5
|
||||
#define PROC_PIDT_SHORTBSDINFO 1
|
||||
#define PROC_PIDT_SHORTBSDINFO_SIZE sizeof(struct proc_bsdshortinfo)
|
||||
#define WNOHANG 1
|
||||
#define LOG_DEBUG 1
|
||||
#define jobmgr_log(...) ((void)0)
|
||||
static jobmgr_t root_jobmgr;
|
||||
static unsigned cursor, waited;
|
||||
static DIR directory;
|
||||
static DIR *opendir(const char *path) {
|
||||
assert(!strcmp(path, "/proc")); cursor = 0; return &directory;
|
||||
}
|
||||
static struct dirent *readdir(DIR *dir) {
|
||||
static struct dirent entry;
|
||||
assert(dir == &directory);
|
||||
if (++cursor > 6) return NULL;
|
||||
snprintf(entry.d_name, sizeof(entry.d_name), "%u", cursor);
|
||||
return &entry;
|
||||
}
|
||||
static int closedir(DIR *dir) { assert(dir == &directory); return 0; }
|
||||
static pid_t getpid(void) { return 100; }
|
||||
static int proc_pidinfo(pid_t pid, int flavor, int arg, void *buffer, size_t size) {
|
||||
struct proc_bsdshortinfo *info = buffer;
|
||||
(void)flavor; (void)arg; assert(size == sizeof(*info));
|
||||
info->pbsi_ppid = pid == 5 ? 200 : 100;
|
||||
info->pbsi_status = pid == 6 ? 1 : SZOMB;
|
||||
return sizeof(*info);
|
||||
}
|
||||
static job_t jobmgr_find_by_pid(jobmgr_t manager, pid_t pid, bool create) {
|
||||
assert(!create);
|
||||
return manager->job && manager->job->pid == pid ? manager->job : NULL;
|
||||
}
|
||||
static job_t jobmgr_find_by_pid_deep(jobmgr_t manager, pid_t pid, bool anon_okay) {
|
||||
job_t job = jobmgr_find_by_pid(manager, pid, false);
|
||||
if (job && (!job->anonymous || anon_okay)) return job;
|
||||
return manager->child ? jobmgr_find_by_pid_deep(manager->child, pid, anon_okay) : NULL;
|
||||
}
|
||||
static pid_t waitpid(pid_t pid, int *status, int flags) {
|
||||
assert(flags == WNOHANG); *status = 0; waited |= 1u << pid; return pid;
|
||||
}
|
||||
''' + reaper + r'''
|
||||
int main(void) {
|
||||
struct job root_job = {1, false}, session_job = {2, false}, anonymous_job = {3, true};
|
||||
struct manager nested = {&anonymous_job, NULL};
|
||||
struct manager session = {&session_job, &nested};
|
||||
struct manager root = {&root_job, &session};
|
||||
root_jobmgr = &root;
|
||||
jobmgr_reap_orphaned_children();
|
||||
/* Root, session and anonymous jobs retain their wait status. Only PID 4
|
||||
* is an untracked zombie child; PID 5 has another parent, PID 6 is alive. */
|
||||
assert(waited == (1u << 4));
|
||||
root_jobmgr = NULL;
|
||||
jobmgr_reap_orphaned_children();
|
||||
assert(waited == (1u << 4));
|
||||
}
|
||||
''')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user