def_run_pip(args, additional_paths=None): # Run the bootstrapping in a subprocess to avoid leaking any state that happens # after pip has executed. Particularly, this avoids the case when pip holds onto # the files in *additional_paths*, preventing us to remove them at the end of the # invocation. code = f""" import runpy import sys sys.path = {additional_paths or []} + sys.path sys.argv[1:] = {args} runpy.run_module("pip", run_name="__main__", alter_sys=True) """
cmd = [ sys.executable, '-W', 'ignore::DeprecationWarning', '-c', code, ] if sys.flags.isolated: # run code in isolated mode if currently running isolated cmd.insert(1, '-I') return subprocess.run(cmd, check=True).returncode
#1 0x00007ffff7d3eeb3 in __pthread_kill_internal (threadid=<optimized out>, signo=6) at pthread_kill.c:78 #2 0x00007ffff7ce6a30 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26 #3 0x00007ffff7cce4c3 in __GI_abort () at abort.c:79 #4 0x00007ffff7cce3df in __assert_fail_base (fmt=0x7ffff7e59b68 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x55555591a150 "tstate->datastack_top < tstate->datastack_limit", file=file@entry=0x555555901138 "./Include/internal/pycore_frame.h", line=line@entry=284, function=function@entry=0x555555977030 <__PRETTY_FUNCTION__.30> "_PyFrame_PushUnchecked") at assert.c:94 #5 0x00007ffff7cdec67 in __assert_fail (assertion=assertion@entry=0x55555591a150 "tstate->datastack_top < tstate->datastack_limit", file=file@entry=0x555555901138 "./Include/internal/pycore_frame.h", line=line@entry=284, function=function@entry=0x555555977030 <__PRETTY_FUNCTION__.30> "_PyFrame_PushUnchecked") at assert.c:103 #6 0x000055555578ec88 in _PyFrame_PushUnchecked (tstate=tstate@entry=0x555555d9e0c0 <_PyRuntime+293952>, func=<optimized out>, null_locals_from=null_locals_from@entry=3) at ./Include/internal/pycore_frame.h:284 #7 0x00005555557b8c51 in _PyEval_EvalFrameDefault (tstate=0x555555d9e0c0 <_PyRuntime+293952>, frame=0x7ffff7f98e58, throwflag=0) at Python/executor_cases.c.h:3326 #8 0x00005555557bc37e in _PyEval_EvalFrame (tstate=tstate@entry=0x555555d9e0c0 <_PyRuntime+293952>, frame=<optimized out>, throwflag=throwflag@entry=0) at ./Include/internal/pycore_ceval.h:118 #9 0x00005555557bc4a4 in _PyEval_Vector (tstate=0x555555d9e0c0 <_PyRuntime+293952>, func=0x7ffff6fe10d0, locals=locals@entry=0x0, args=0x7fffffff15e0, argcount=2, kwnames=0x0) at Python/ceval.c:1818 #10 0x00005555556728e4 in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:413 #11 0x0000555555672c54 in _PyObject_VectorcallTstate (tstate=tstate@entry=0x555555d9e0c0 <_PyRuntime+293952>, callable=callable@entry=<function at remote 0x7ffff6fe10d0>, args=args@entry=0x7fffffff15e0, nargsf=nargsf@entry=2, kwnames=kwnames@entry=0x0) at ./Include/internal/pycore_call.h:168 #12 0x0000555555673b8c in object_vacall (tstate=tstate@entry=0x555555d9e0c0 <_PyRuntime+293952>, base=base@entry=0x0, callable=<function at remote 0x7ffff6fe10d0>, vargs=vargs@entry=0x7fffffff1660) at Objects/call.c:819 #13 0x0000555555673cea in PyObject_CallMethodObjArgs (obj=0x0, name=<optimized out>) at Objects/call.c:880 #14 0x00005555557fb230 in import_find_and_load (tstate=tstate@entry=0x555555d9e0c0 <_PyRuntime+293952>, abs_name=abs_name@entry='_winapi') at Python/import.c:3080 #15 0x00005555557feb3a in PyImport_ImportModuleLevelObject (name=name@entry='_winapi', globals=<optimized out>, locals=locals@entry={'__name__': 'mimetypes', '__doc__': 'Guess the MIME type of a file.\n\nThis module defines two useful functions:\n\nguess_type(url, strict=True) -- guess the MIME type and encoding of a URL.\n\nguess_extension(type, strict=True) -- guess the extension for a given MIME type.\n\nIt also contains the following, for tuning the behavior:\n\nData:\n\nknownfiles -- list of files to parse\ninited -- flag set when init() has been called\nsuffix_map -- dictionary mapping suffixes to suffixes\nencodings_map -- dictionary mapping suffixes to encodings\ntypes_map -- dictionary mapping suffixes to types\n\nFunctions:\n\ninit([files]) -- parse a list of files, default knownfiles (on Windows, the\n default values are taken from the registry)\nread_mime_types(file) -- parse one file, return a dictionary or None\n', '__package__': '', '__loader__': <SourceFileLoader(name='mimetypes', path='/home/manjusaka/Documents/projects/cpython/Lib/mimetypes.py') at remote 0x7ffff5395100>, '__spec__': <ModuleSpec(name='mimetypes', loader...(truncated), fromlist=fromlist@entry=('_mimetypes_read_windows_registry',), level=level@entry=0) at Python/import.c:3160 #16 0x000055555578f3fa in import_name (tstate=tstate@entry=0x555555d9e0c0 <_PyRuntime+293952>, frame=frame@entry=0x7ffff7f98b18, name='_winapi', fromlist=fromlist@entry=('_mimetypes_read_windows_registry',), level=level@entry=0) at Python/ceval.c:2629 #17 0x00005555557a244b in _PyEval_EvalFrameDefault (tstate=0x555555d9e0c0 <_PyRuntime+293952>, frame=0x7ffff7f98b18, throwflag=0) at Python/generated_cases.c.h:3196 #18 0x00005555557bc37e in _PyEval_EvalFrame (tstate=tstate@entry=0x555555d9e0c0 <_PyRuntime+293952>, frame=<optimized out>, throwflag=throwflag@entry=0) at ./Include/internal/pycore_ceval.h:118
这个栈看着就轻松很多了,我们很轻松的来到 #7 ,判断出当前的 opcode _INIT_CALL_PY_EXACT_ARGS_x,这是一个 Tier2 的特化指令,这里可以近似的认为我们对于这个指令有足够的上下文,比如函数初始化的时候参数有两个(对应此处的 _INIT_CALL_PY_EXACT_ARGS_2),然后有一些 short pass,在这个 short pass 中,_PyFrame_PushUnchecked 会被快速调用(免去了额外的 frame 大小的校验)。那么我最开始的想法是这样,我可以在这个指令的特化逻辑加一个额外的 check,如果当前的线程状态中保存的栈大小小于我们需要的大小,那么则退出特化,走传统的调用方式,那么更改起来也相对简单,_INIT_CALL_PY_EXACT_ARGS_x 有一个前置指令是 _CHECK_FUNCTION_EXACT_ARGS