this repo has no description
at trunk 475 lines 22 kB view raw
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