Fix exec in prewarm forked process sometimes inheriting env vars from grandparent process
This commit is contained in:
parent
1ba027c277
commit
89a0c04d19
@ -181,8 +181,26 @@ spawn(PyObject *self UNUSED, PyObject *args) {
|
|||||||
return PyLong_FromLong(pid);
|
return PyLong_FromLong(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <crt_externs.h>
|
||||||
|
#else
|
||||||
|
extern char **environ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
clearenv_py(PyObject *self UNUSED, PyObject *args UNUSED) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
char **e = *_NSGetEnviron();
|
||||||
|
if (e) *e = NULL;
|
||||||
|
#else
|
||||||
|
if (environ) *environ = NULL;
|
||||||
|
#endif
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
METHODB(spawn, METH_VARARGS),
|
METHODB(spawn, METH_VARARGS),
|
||||||
|
{"clearenv", clearenv_py, METH_NOARGS, ""},
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1485,3 +1485,4 @@ class SingleKey:
|
|||||||
|
|
||||||
def set_use_os_log(yes: bool) -> None: ...
|
def set_use_os_log(yes: bool) -> None: ...
|
||||||
def get_docs_ref_map() -> bytes: ...
|
def get_docs_ref_map() -> bytes: ...
|
||||||
|
def clearenv() -> None: ...
|
||||||
|
|||||||
@ -24,9 +24,9 @@ from typing import (
|
|||||||
from kitty.constants import kitty_exe, running_in_kitty
|
from kitty.constants import kitty_exe, running_in_kitty
|
||||||
from kitty.entry_points import main as main_entry_point
|
from kitty.entry_points import main as main_entry_point
|
||||||
from kitty.fast_data_types import (
|
from kitty.fast_data_types import (
|
||||||
CLD_EXITED, CLD_KILLED, CLD_STOPPED, get_options, install_signal_handlers,
|
CLD_EXITED, CLD_KILLED, CLD_STOPPED, clearenv, get_options,
|
||||||
read_signals, remove_signal_handlers, safe_pipe, set_options,
|
install_signal_handlers, read_signals, remove_signal_handlers, safe_pipe,
|
||||||
set_use_os_log
|
set_options, set_use_os_log
|
||||||
)
|
)
|
||||||
from kitty.options.types import Options
|
from kitty.options.types import Options
|
||||||
from kitty.shm import SharedMemory
|
from kitty.shm import SharedMemory
|
||||||
@ -293,6 +293,13 @@ def child_main(cmd: Dict[str, Any], ready_fd: int = -1, prewarm_type: str = 'dir
|
|||||||
env = cmd.get('env')
|
env = cmd.get('env')
|
||||||
if env is not None:
|
if env is not None:
|
||||||
os.environ.clear()
|
os.environ.clear()
|
||||||
|
# os.environ.clear() does not delete all existing env vars from the
|
||||||
|
# libc environ pointer in some circumstances, I havent figured out
|
||||||
|
# which exactly. Presumably there is something that alters the
|
||||||
|
# libc environ pointer?? The environ pointer is used by os.exec and
|
||||||
|
# therefore by subprocess and friends, so we need to ensure it is
|
||||||
|
# cleared.
|
||||||
|
clearenv()
|
||||||
os.environ.update(env)
|
os.environ.update(env)
|
||||||
argv = cmd.get('argv')
|
argv = cmd.get('argv')
|
||||||
if argv:
|
if argv:
|
||||||
|
|||||||
@ -28,13 +28,15 @@ class Prewarm(BaseTest):
|
|||||||
|
|
||||||
cwd = tempfile.gettempdir()
|
cwd = tempfile.gettempdir()
|
||||||
env = {'TEST_ENV_PASS': 'xyz'}
|
env = {'TEST_ENV_PASS': 'xyz'}
|
||||||
cols = 117
|
cols = 317
|
||||||
stdin_data = 'from_stdin'
|
stdin_data = 'from_stdin'
|
||||||
pty = self.create_pty(cols=cols)
|
pty = self.create_pty(cols=cols)
|
||||||
ttyname = os.ttyname(pty.slave_fd)
|
ttyname = os.ttyname(pty.slave_fd)
|
||||||
opts = get_options()
|
opts = get_options()
|
||||||
opts.config_overrides = 'font_family prewarm',
|
opts.config_overrides = 'font_family prewarm',
|
||||||
|
os.environ['SHOULD_NOT_BE_PRESENT'] = '1'
|
||||||
p = fork_prewarm_process(opts, use_exec=True)
|
p = fork_prewarm_process(opts, use_exec=True)
|
||||||
|
del os.environ['SHOULD_NOT_BE_PRESENT']
|
||||||
if p is None:
|
if p is None:
|
||||||
return
|
return
|
||||||
p.take_from_worker_fd(create_file=True)
|
p.take_from_worker_fd(create_file=True)
|
||||||
@ -44,7 +46,7 @@ import os, json; from kitty.utils import *; from kitty.fast_data_types import ge
|
|||||||
'ttyname': os.ttyname(sys.stdout.fileno()),
|
'ttyname': os.ttyname(sys.stdout.fileno()),
|
||||||
'cols': read_screen_size().cols,
|
'cols': read_screen_size().cols,
|
||||||
'cwd': os.getcwd(),
|
'cwd': os.getcwd(),
|
||||||
'env': os.environ.get('TEST_ENV_PASS'),
|
'env': os.environ.copy(),
|
||||||
'pid': os.getpid(),
|
'pid': os.getpid(),
|
||||||
'font_family': get_options().font_family,
|
'font_family': get_options().font_family,
|
||||||
'stdin': sys.stdin.read(),
|
'stdin': sys.stdin.read(),
|
||||||
@ -59,7 +61,8 @@ import os, json; from kitty.utils import *; from kitty.fast_data_types import ge
|
|||||||
self.assertTrue(data['cterm'])
|
self.assertTrue(data['cterm'])
|
||||||
self.ae(data['ttyname'], ttyname)
|
self.ae(data['ttyname'], ttyname)
|
||||||
self.ae(os.path.realpath(data['cwd']), os.path.realpath(cwd))
|
self.ae(os.path.realpath(data['cwd']), os.path.realpath(cwd))
|
||||||
self.ae(data['env'], env['TEST_ENV_PASS'])
|
self.ae(data['env']['TEST_ENV_PASS'], env['TEST_ENV_PASS'])
|
||||||
|
self.assertNotIn('SHOULD_NOT_BE_PRESENT', data['env'])
|
||||||
self.ae(data['font_family'], 'prewarm')
|
self.ae(data['font_family'], 'prewarm')
|
||||||
self.ae(int(p.from_worker.readline()), data['pid'])
|
self.ae(int(p.from_worker.readline()), data['pid'])
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user