this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <signal.h>
3#include <unistd.h>
4
5#include <cerrno>
6#include <clocale>
7#include <cstdio>
8#include <cstdlib>
9
10#include "cpython-data.h"
11#include "cpython-func.h"
12
13#include "api-handle.h"
14#include "capi.h"
15#include "exception-builtins.h"
16#include "file.h"
17#include "modules.h"
18#include "os.h"
19#include "runtime.h"
20#include "str-builtins.h"
21#include "sys-module.h"
22#include "vector.h"
23
24extern "C" int _PyCapsule_Init(void);
25extern "C" int _PySTEntry_Init(void);
26
27int Py_BytesWarningFlag = 0;
28int Py_DebugFlag = 0;
29int Py_DontWriteBytecodeFlag = 0;
30int Py_FrozenFlag = 0;
31int Py_HashRandomizationFlag = 0;
32int Py_IgnoreEnvironmentFlag = 0;
33int Py_InspectFlag = 0;
34int Py_InteractiveFlag = 0;
35int Py_IsolatedFlag = 0;
36int Py_NoSiteFlag = 0;
37int Py_NoUserSiteDirectory = 0;
38int Py_OptimizeFlag = 0;
39int Py_QuietFlag = 0;
40int Py_UTF8Mode = 1;
41int Py_UnbufferedStdioFlag = 0;
42int Py_VerboseFlag = 0;
43
44namespace py {
45
46// Used by Py_BytesMain to store `-W` options. `Py_Initialize` will read
47// them and clear the vector.
48Vector<const char*> warn_options;
49
50PY_EXPORT PyOS_sighandler_t PyOS_getsig(int signum) {
51 return OS::signalHandler(signum);
52}
53
54PY_EXPORT PyOS_sighandler_t PyOS_setsig(int signum, PyOS_sighandler_t handler) {
55 return OS::setSignalHandler(signum, handler);
56}
57
58PY_EXPORT int Py_AtExit(void (*/* func */)(void)) {
59 UNIMPLEMENTED("Py_AtExit");
60}
61
62PY_EXPORT void Py_EndInterpreter(PyThreadState* /* e */) {
63 UNIMPLEMENTED("Py_EndInterpreter");
64}
65
66PY_EXPORT void Py_Exit(int status_code) {
67 if (Py_FinalizeEx() < 0) {
68 status_code = 120;
69 }
70
71 std::exit(status_code);
72}
73
74PY_EXPORT void _Py_NO_RETURN Py_FatalError(const char* msg) {
75 // TODO(T39151288): Correctly print exceptions when the current thread holds
76 // the GIL
77 std::fprintf(stderr, "Fatal Python error: %s\n", msg);
78 Thread* thread = Thread::current();
79 if (thread != nullptr) {
80 if (thread->hasPendingException()) {
81 printPendingException(thread);
82 } else {
83 thread->runtime()->printTraceback(thread, File::kStderr);
84 }
85 }
86 std::abort();
87}
88
89// The file descriptor fd is considered ``interactive'' if either:
90// a) isatty(fd) is TRUE, or
91// b) the -i flag was given, and the filename associated with the descriptor
92// is NULL or "<stdin>" or "???".
93PY_EXPORT int Py_FdIsInteractive(FILE* fp, const char* filename) {
94 if (::isatty(fileno(fp))) {
95 return 1;
96 }
97 if (!Py_InteractiveFlag) {
98 return 0;
99 }
100 return filename == nullptr || std::strcmp(filename, "<stdin>") == 0 ||
101 std::strcmp(filename, "???") == 0;
102}
103
104PY_EXPORT void Py_Finalize() { Py_FinalizeEx(); }
105
106// TODO(T70098990): Implement and add PyEnum_Type
107
108#define FOREACH_STATICTYPE(V) \
109 V(PyAsyncGen_Type) \
110 V(PyBaseObject_Type) \
111 V(PyBool_Type) \
112 V(PyByteArrayIter_Type) \
113 V(PyByteArray_Type) \
114 V(PyBytesIter_Type) \
115 V(PyBytes_Type) \
116 V(PyClassMethod_Type) \
117 V(PyCode_Type) \
118 V(PyComplex_Type) \
119 V(PyCoro_Type) \
120 V(PyDictItems_Type) \
121 V(PyDictIterItem_Type) \
122 V(PyDictIterKey_Type) \
123 V(PyDictIterValue_Type) \
124 V(PyDictKeys_Type) \
125 V(PyDictProxy_Type) \
126 V(PyDictValues_Type) \
127 V(PyDict_Type) \
128 V(PyEllipsis_Type) \
129 V(PyEnum_Type) \
130 V(PyFloat_Type) \
131 V(PyFrozenSet_Type) \
132 V(PyFunction_Type) \
133 V(PyGen_Type) \
134 V(PyListIter_Type) \
135 V(PyList_Type) \
136 V(PyLongRangeIter_Type) \
137 V(PyLong_Type) \
138 V(PyMemoryView_Type) \
139 V(PyMethod_Type) \
140 V(PyModule_Type) \
141 V(PyProperty_Type) \
142 V(PyRangeIter_Type) \
143 V(PyRange_Type) \
144 V(PySeqIter_Type) \
145 V(PySetIter_Type) \
146 V(PySet_Type) \
147 V(PySlice_Type) \
148 V(PyStaticMethod_Type) \
149 V(PySuper_Type) \
150 V(PyTupleIter_Type) \
151 V(PyTuple_Type) \
152 V(PyType_Type) \
153 V(PyUnicodeIter_Type) \
154 V(PyUnicode_Type) \
155 V(_PyNone_Type) \
156 V(_PyNotImplemented_Type)
157
158#define FOREACH_POINTER(V) \
159 V(PyExc_ArithmeticError) \
160 V(PyExc_AssertionError) \
161 V(PyExc_AttributeError) \
162 V(PyExc_BaseException) \
163 V(PyExc_BlockingIOError) \
164 V(PyExc_BrokenPipeError) \
165 V(PyExc_BufferError) \
166 V(PyExc_BytesWarning) \
167 V(PyExc_ChildProcessError) \
168 V(PyExc_ConnectionAbortedError) \
169 V(PyExc_ConnectionError) \
170 V(PyExc_ConnectionRefusedError) \
171 V(PyExc_ConnectionResetError) \
172 V(PyExc_DeprecationWarning) \
173 V(PyExc_EOFError) \
174 V(PyExc_EnvironmentError) \
175 V(PyExc_Exception) \
176 V(PyExc_FileExistsError) \
177 V(PyExc_FileNotFoundError) \
178 V(PyExc_FloatingPointError) \
179 V(PyExc_FutureWarning) \
180 V(PyExc_GeneratorExit) \
181 V(PyExc_IOError) \
182 V(PyExc_ImportError) \
183 V(PyExc_ImportWarning) \
184 V(PyExc_IndentationError) \
185 V(PyExc_IndexError) \
186 V(PyExc_InterruptedError) \
187 V(PyExc_IsADirectoryError) \
188 V(PyExc_KeyError) \
189 V(PyExc_KeyboardInterrupt) \
190 V(PyExc_LookupError) \
191 V(PyExc_MemoryError) \
192 V(PyExc_ModuleNotFoundError) \
193 V(PyExc_NameError) \
194 V(PyExc_NotADirectoryError) \
195 V(PyExc_NotImplementedError) \
196 V(PyExc_OSError) \
197 V(PyExc_OverflowError) \
198 V(PyExc_PendingDeprecationWarning) \
199 V(PyExc_PermissionError) \
200 V(PyExc_ProcessLookupError) \
201 V(PyExc_RecursionError) \
202 V(PyExc_ReferenceError) \
203 V(PyExc_ResourceWarning) \
204 V(PyExc_RuntimeError) \
205 V(PyExc_RuntimeWarning) \
206 V(PyExc_StopAsyncIteration) \
207 V(PyExc_StopIteration) \
208 V(PyExc_SyntaxError) \
209 V(PyExc_SyntaxWarning) \
210 V(PyExc_SystemError) \
211 V(PyExc_SystemExit) \
212 V(PyExc_TabError) \
213 V(PyExc_TimeoutError) \
214 V(PyExc_TypeError) \
215 V(PyExc_UnboundLocalError) \
216 V(PyExc_UnicodeDecodeError) \
217 V(PyExc_UnicodeEncodeError) \
218 V(PyExc_UnicodeError) \
219 V(PyExc_UnicodeTranslateError) \
220 V(PyExc_UnicodeWarning) \
221 V(PyExc_UserWarning) \
222 V(PyExc_ValueError) \
223 V(PyExc_Warning) \
224 V(PyExc_ZeroDivisionError) \
225 V(Py_Ellipsis) \
226 V(Py_False) \
227 V(Py_None) \
228 V(Py_NotImplemented) \
229 V(Py_True) \
230 V(_PyLong_One) \
231 V(_PyLong_Zero)
232
233void finalizeCAPIModules() {
234#define DECREF(ptr) Py_DECREF(&ptr);
235 FOREACH_STATICTYPE(DECREF);
236#undef DECREF
237#define DECREF(ptr) Py_DECREF(ptr);
238 FOREACH_POINTER(DECREF)
239#undef DECREF
240}
241
242void initializeCAPIModules() {
243 CHECK(_PyCapsule_Init() == 0, "Failed to initialize PyCapsule");
244 CHECK(_PySTEntry_Init() == 0, "Failed to initialize PySTEntry");
245 // Even though our runtime keeps objects like the `dict` type alive, the
246 // handle (`PyDict_Type`) may not live as long. This is because we are using
247 // a borrowedReference to simulate CPython's reference to a static type. To
248 // mitigate this, incref each well-known handle name once in initialization
249 // and decref it again in finalization.
250#define INCREF(ptr) Py_INCREF(&ptr);
251 FOREACH_STATICTYPE(INCREF);
252#undef INCREF
253#define INCREF(ptr) Py_INCREF(ptr);
254 FOREACH_POINTER(INCREF)
255#undef INCREF
256}
257
258PY_EXPORT int Py_FinalizeEx() {
259 Thread* thread = Thread::current();
260 Runtime* runtime = thread->runtime();
261 delete runtime;
262 return 0;
263}
264
265static bool boolFromEnv(const char* name, bool default_value) {
266 if (Py_IgnoreEnvironmentFlag) return default_value;
267 const char* value = std::getenv(name);
268 if (value == nullptr) return default_value;
269 if (std::strcmp(value, "0") == 0) return false;
270 if (std::strcmp(value, "1") == 0) return true;
271 fprintf(stderr, "Error: Environment variable '%s' must be '0' or '1'\n",
272 name);
273 return default_value;
274}
275
276PY_EXPORT void Py_Initialize() { Py_InitializeEx(1); }
277
278static void initializeSysFromGlobals(Thread* thread) {
279 HandleScope scope(thread);
280 Runtime* runtime = thread->runtime();
281 unique_c_ptr<char> path(OS::executablePath());
282 Str executable(&scope, runtime->newStrFromCStr(path.get()));
283
284 Object python_path_obj(&scope, NoneType::object());
285 const wchar_t* explicitly_provided_module_search_path =
286 Runtime::moduleSearchPath();
287 bool has_explicitly_provided_module_search_path =
288 explicitly_provided_module_search_path[0] != L'\0';
289 if (has_explicitly_provided_module_search_path) {
290 // TODO(T88306794): Instead of passing in the python path to initializeSys,
291 // we should indicate that binary_location/../lib should not be included in
292 // the search path when an explicit module search path is provided.
293 Str python_path_str(
294 &scope,
295 newStrFromWideChar(thread, explicitly_provided_module_search_path));
296 Str sep(&scope, SmallStr::fromCStr(":"));
297 python_path_obj = strSplit(thread, python_path_str, sep, kMaxWord);
298 CHECK(!python_path_obj.isError(),
299 "Failed to calculate path provided by `Py_SetPath`.");
300 } else {
301 const char* python_path_cstr =
302 Py_IgnoreEnvironmentFlag ? nullptr : std::getenv("PYTHONPATH");
303 if (python_path_cstr != nullptr) {
304 Str python_path_str(&scope, runtime->newStrFromCStr(python_path_cstr));
305 Str sep(&scope, SmallStr::fromCStr(":"));
306 python_path_obj = strSplit(thread, python_path_str, sep, kMaxWord);
307 CHECK(!python_path_obj.isError(), "Failed to calculate PYTHONPATH");
308 } else {
309 python_path_obj = runtime->newList();
310 }
311 }
312 List python_path(&scope, *python_path_obj);
313 const char* warnoptions_cstr =
314 Py_IgnoreEnvironmentFlag ? nullptr : std::getenv("PYTHONWARNINGS");
315 Object warnoptions_obj(&scope, NoneType::object());
316 if (warnoptions_cstr != nullptr) {
317 Str warnoptions_str(&scope, runtime->newStrFromCStr(warnoptions_cstr));
318 Str sep(&scope, SmallStr::fromCStr(","));
319 warnoptions_obj = strSplit(thread, warnoptions_str, sep, kMaxWord);
320 } else {
321 warnoptions_obj = runtime->newList();
322 }
323 List warnoptions(&scope, *warnoptions_obj);
324 Object option(&scope, NoneType::object());
325 for (word i = 0, size = warn_options.size(); i < size; i++) {
326 option = runtime->newStrFromCStr(warn_options[i]);
327 runtime->listAdd(thread, warnoptions, option);
328 }
329 warn_options.release();
330
331 const char* pycache_prefix_cstr =
332 Py_IgnoreEnvironmentFlag ? nullptr : std::getenv("PYTHONPYCACHEPREFIX");
333 if (pycache_prefix_cstr != nullptr) {
334 Str pycache_prefix_str(&scope,
335 runtime->newStrFromCStr(pycache_prefix_cstr));
336 setPycachePrefix(thread, pycache_prefix_str);
337 }
338
339 MutableTuple data(
340 &scope, runtime->newMutableTuple(static_cast<word>(SysFlag::kNumFlags)));
341 data.atPut(static_cast<word>(SysFlag::kDebug),
342 SmallInt::fromWord(Py_DebugFlag));
343 data.atPut(static_cast<word>(SysFlag::kInspect),
344 SmallInt::fromWord(Py_InspectFlag));
345 data.atPut(static_cast<word>(SysFlag::kInteractive),
346 SmallInt::fromWord(Py_InteractiveFlag));
347 data.atPut(static_cast<word>(SysFlag::kOptimize),
348 SmallInt::fromWord(Py_OptimizeFlag));
349 data.atPut(static_cast<word>(SysFlag::kDontWriteBytecode),
350 SmallInt::fromWord(Py_DontWriteBytecodeFlag));
351 data.atPut(static_cast<word>(SysFlag::kNoUserSite),
352 SmallInt::fromWord(Py_NoUserSiteDirectory));
353 data.atPut(static_cast<word>(SysFlag::kNoSite),
354 SmallInt::fromWord(Py_NoSiteFlag));
355 data.atPut(static_cast<word>(SysFlag::kIgnoreEnvironment),
356 SmallInt::fromWord(Py_IgnoreEnvironmentFlag));
357 data.atPut(static_cast<word>(SysFlag::kVerbose),
358 SmallInt::fromWord(Py_VerboseFlag));
359 data.atPut(static_cast<word>(SysFlag::kBytesWarning),
360 SmallInt::fromWord(Py_BytesWarningFlag));
361 data.atPut(static_cast<word>(SysFlag::kQuiet),
362 SmallInt::fromWord(Py_QuietFlag));
363 data.atPut(static_cast<word>(SysFlag::kHashRandomization),
364 SmallInt::fromWord(Py_HashRandomizationFlag));
365 data.atPut(static_cast<word>(SysFlag::kIsolated),
366 SmallInt::fromWord(Py_IsolatedFlag));
367 data.atPut(static_cast<word>(SysFlag::kDevMode), Bool::falseObj());
368 data.atPut(static_cast<word>(SysFlag::kUTF8Mode),
369 SmallInt::fromWord(Py_UTF8Mode));
370 static_assert(static_cast<word>(SysFlag::kNumFlags) == 15,
371 "unexpected flag count");
372 Tuple flags_data(&scope, data.becomeImmutable());
373 CHECK(initializeSys(thread, executable, python_path, flags_data, warnoptions,
374 /*extend_python_path_with_stdlib=*/
375 !has_explicitly_provided_module_search_path)
376 .isNoneType(),
377 "initializeSys() failed");
378}
379
380PY_EXPORT void Py_InitializeEx(int initsigs) {
381 CHECK(Py_BytesWarningFlag == 0, "Py_BytesWarningFlag != 0 not supported");
382 CHECK(Py_DebugFlag == 0, "parser debug mode not supported");
383 CHECK(Py_UTF8Mode == 1, "UTF8Mode != 1 not supported");
384 CHECK(initsigs == 1, "Skipping signal handler registration unimplemented");
385 // TODO(T63603973): Reduce initial heap size once we can auto-grow the heap
386 word heap_size = word{2} * kGiB;
387 RandomState random_seed;
388 const char* hashseed =
389 Py_IgnoreEnvironmentFlag ? nullptr : std::getenv("PYTHONHASHSEED");
390 if (hashseed != nullptr && hashseed[0] != '\0' &&
391 std::strcmp(hashseed, "random") != 0) {
392 char* endptr;
393 unsigned long seed = std::strtoul(hashseed, &endptr, 10);
394 if (*endptr != '\0' || seed > 4294967295 ||
395 (seed == ULONG_MAX && errno == ERANGE)) {
396 Py_FatalError(
397 "PYTHONHASHSEED must be \"random\" or an integer in range [0; "
398 "4294967295]");
399 }
400 random_seed = randomStateFromSeed(static_cast<uint64_t>(seed));
401 Py_HashRandomizationFlag = (seed != 0);
402 } else {
403 random_seed = randomState();
404 Py_HashRandomizationFlag = 1;
405 }
406 StdioState stdio_state =
407 Py_UnbufferedStdioFlag ? StdioState::kUnbuffered : StdioState::kBuffered;
408 Interpreter* interpreter = boolFromEnv("PYRO_CPP_INTERPRETER", false)
409 ? createCppInterpreter()
410 : createAsmInterpreter();
411 Runtime* runtime =
412 new Runtime(heap_size, interpreter, random_seed, stdio_state);
413 Thread* thread = Thread::current();
414 initializeSysFromGlobals(thread);
415 CHECK(runtime->initialize(thread).isNoneType(),
416 "Failed to initialize runtime");
417}
418
419PY_EXPORT int Py_IsInitialized() {
420 Thread* thread = Thread::current();
421 if (thread == nullptr) {
422 return 0;
423 }
424 Runtime* runtime = thread->runtime();
425 CHECK(runtime != nullptr, "runtime is expected not to be null");
426 return runtime->initialized();
427}
428
429PY_EXPORT PyThreadState* Py_NewInterpreter() {
430 UNIMPLEMENTED("Py_NewInterpreter");
431}
432
433struct AtExitContext {
434 void (*func)(PyObject*);
435 PyObject* module;
436};
437
438static void callAtExitFunction(void* context) {
439 DCHECK(context != nullptr, "context must not be null");
440 AtExitContext* thunk = reinterpret_cast<AtExitContext*>(context);
441 DCHECK(thunk->func != nullptr, "function must not be null");
442 thunk->func(thunk->module);
443 // CPython does not own the reference, but that's dangerous.
444 Py_DECREF(thunk->module);
445 PyErr_Clear();
446 delete thunk;
447}
448
449PY_EXPORT void _Py_PyAtExit(void (*func)(PyObject*), PyObject* module) {
450 AtExitContext* thunk = new AtExitContext;
451 thunk->func = func;
452 // CPython does not own the reference, but that's dangerous.
453 Py_INCREF(module);
454 thunk->module = module;
455 Thread::current()->runtime()->setAtExit(callAtExitFunction, thunk);
456}
457
458PY_EXPORT void _Py_RestoreSignals() {
459 PyOS_setsig(SIGPIPE, SIG_DFL);
460 PyOS_setsig(SIGXFSZ, SIG_DFL);
461}
462
463// NOTE: this implementation does not work for Android
464PY_EXPORT char* _Py_SetLocaleFromEnv(int category) {
465 return std::setlocale(category, "");
466}
467
468PY_EXPORT int _Py_IsFinalizing(void) {
469 if (Thread::current() == nullptr) return 0;
470 Runtime* runtime = Thread::current()->runtime();
471 DCHECK(runtime != nullptr, "unexpected");
472 return runtime->isFinalizing();
473}
474
475} // namespace py