this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "cpython-data.h"
3#include "cpython-func.h"
4
5#include "api-handle.h"
6#include "builtins-module.h"
7#include "compile-utils.h"
8#include "exception-builtins.h"
9#include "fileutils.h"
10#include "marshal.h"
11#include "module-builtins.h"
12#include "modules.h"
13#include "object-builtins.h"
14#include "os.h"
15#include "runtime.h"
16#include "sys-module.h"
17
18namespace py {
19
20PY_EXPORT PyObject* Py_CompileString(const char* str, const char* filename,
21 int start) {
22 DCHECK(str != nullptr, "str must not be null");
23 DCHECK(filename != nullptr, "filename must not be null");
24 PyObject* filename_obj = PyUnicode_DecodeFSDefault(filename);
25 if (filename_obj == nullptr) return nullptr;
26
27 PyArena* arena = PyArena_New();
28 if (arena == nullptr) {
29 Py_DECREF(filename_obj);
30 return nullptr;
31 }
32
33 struct _mod* mod =
34 PyParser_ASTFromStringObject(str, filename_obj, start, nullptr, arena);
35 if (mod == nullptr) {
36 PyArena_Free(arena);
37 Py_DECREF(filename_obj);
38 return nullptr;
39 }
40 PyObject* result = reinterpret_cast<PyObject*>(
41 PyAST_CompileObject(mod, filename_obj, nullptr, -1, arena));
42 PyArena_Free(arena);
43 Py_DECREF(filename_obj);
44 return result;
45}
46
47PY_EXPORT int PyRun_AnyFile(FILE* fp, const char* filename) {
48 return PyRun_AnyFileExFlags(fp, filename, /*closeit=*/0, /*flags=*/nullptr);
49}
50
51PY_EXPORT int PyRun_AnyFileEx(FILE* fp, const char* filename, int closeit) {
52 return PyRun_AnyFileExFlags(fp, filename, closeit, /*flags=*/nullptr);
53}
54
55PY_EXPORT int PyRun_AnyFileExFlags(FILE* fp, const char* filename, int closeit,
56 PyCompilerFlags* flags) {
57 if (filename == nullptr) {
58 filename = "???";
59 }
60 if (Py_FdIsInteractive(fp, filename)) {
61 int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
62 if (closeit) fclose(fp);
63 return err;
64 }
65 return PyRun_SimpleFileExFlags(fp, filename, closeit, flags);
66}
67
68PY_EXPORT int PyRun_AnyFileFlags(FILE* fp, const char* filename,
69 PyCompilerFlags* flags) {
70 return PyRun_AnyFileExFlags(fp, filename, /*closeit=*/0, flags);
71}
72
73static PyObject* runMod(struct _mod* mod, PyObject* filename, PyObject* globals,
74 PyObject* locals, PyCompilerFlags* flags,
75 PyArena* arena) {
76 PyCodeObject* code = PyAST_CompileObject(mod, filename, flags, -1, arena);
77 if (code == nullptr) return nullptr;
78 PyObject* v =
79 PyEval_EvalCode(reinterpret_cast<PyObject*>(code), globals, locals);
80 Py_DECREF(code);
81 return v;
82}
83
84static PyObject* runPycFile(FILE* fp, const char* filename, Module& module,
85 PyCompilerFlags* flags) {
86 Thread* thread = Thread::current();
87 Runtime* runtime = thread->runtime();
88 HandleScope scope(thread);
89
90 word file_len;
91 unique_c_ptr<byte> buffer(OS::readFile(fp, &file_len));
92 if (buffer == nullptr) {
93 std::fprintf(stderr, "Could not read file '%s'\n", filename);
94 std::fclose(fp);
95 return nullptr;
96 }
97
98 Object code_obj(&scope, NoneType::object());
99 Marshal::Reader reader(&scope, thread, View<byte>(buffer.get(), file_len));
100 Str filename_str(&scope, runtime->newStrFromCStr(filename));
101 if (reader.readPycHeader(filename_str).isErrorException()) {
102 return nullptr;
103 }
104 code_obj = reader.readObject();
105 std::fclose(fp);
106
107 Code code(&scope, *code_obj);
108 RawObject result = executeModule(thread, code, module);
109 if (!result.isError() && flags) {
110 flags->cf_flags |= (code.flags() & PyCF_MASK);
111 }
112 return result.isError() ? nullptr : ApiHandle::newReference(runtime, result);
113}
114
115static PyObject* moduleProxy(PyObject* module_obj) {
116 Thread* thread = Thread::current();
117 HandleScope scope(thread);
118 Module module(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(module_obj)));
119 return ApiHandle::borrowedReference(thread->runtime(), module.moduleProxy());
120}
121
122// A PyRun_InteractiveOneObject() auxiliary function that does not print the
123// error on failure.
124static int PyRun_InteractiveOneObjectEx(FILE* fp, PyObject* filename,
125 PyCompilerFlags* flags) {
126 PyObject* mod_name = PyUnicode_InternFromString("__main__");
127 if (mod_name == nullptr) {
128 return -1;
129 }
130 // TODO(T46532201): If fp == stdin, fetch encoding from sys.stdin if possible
131 const char* ps1 = "";
132 const char* ps2 = "";
133 PyObject* ps1_obj = PySys_GetObject("ps1");
134 if (ps1_obj != nullptr) {
135 if ((ps1_obj = PyObject_Str(ps1_obj)) == nullptr) {
136 PyErr_Clear();
137 } else if (PyUnicode_Check(ps1_obj)) {
138 if ((ps1 = PyUnicode_AsUTF8(ps1_obj)) == nullptr) {
139 PyErr_Clear();
140 ps1 = "";
141 }
142 }
143 Py_XDECREF(ps1_obj);
144 }
145 PyObject* ps2_obj = PySys_GetObject("ps2");
146 if (ps2_obj != nullptr) {
147 if ((ps2_obj = PyObject_Str(ps2_obj)) == nullptr) {
148 PyErr_Clear();
149 } else if (PyUnicode_Check(ps2_obj)) {
150 if ((ps2 = PyUnicode_AsUTF8(ps2_obj)) == nullptr) {
151 PyErr_Clear();
152 ps2 = "";
153 }
154 }
155 Py_XDECREF(ps2_obj);
156 }
157 PyArena* arena = PyArena_New();
158 if (arena == nullptr) {
159 Py_DECREF(mod_name);
160 return -1;
161 }
162 char* enc = nullptr;
163 int errcode = 0;
164 struct _mod* mod = PyParser_ASTFromFileObject(
165 fp, filename, enc, Py_single_input, ps1, ps2, flags, &errcode, arena);
166 if (mod == nullptr) {
167 Py_DECREF(mod_name);
168 PyArena_Free(arena);
169 if (errcode == E_EOF) {
170 PyErr_Clear();
171 return E_EOF;
172 }
173 return -1;
174 }
175 PyObject* module = PyImport_AddModuleObject(mod_name);
176 Py_DECREF(mod_name);
177 if (module == nullptr) {
178 PyArena_Free(arena);
179 return -1;
180 }
181 PyObject* module_proxy = moduleProxy(module);
182 PyObject* result = runMod(mod, filename, /*globals=*/module_proxy,
183 /*locals=*/module_proxy, flags, arena);
184 PyArena_Free(arena);
185 if (result == nullptr) {
186 return -1;
187 }
188 Py_DECREF(result);
189 flushStdFiles();
190 return 0;
191}
192
193PY_EXPORT int PyRun_InteractiveLoop(FILE* fp, const char* filename) {
194 return PyRun_InteractiveLoopFlags(fp, filename, /*flags=*/nullptr);
195}
196
197PY_EXPORT int PyRun_InteractiveLoopFlags(FILE* fp, const char* filename,
198 PyCompilerFlags* flags) {
199 PyObject* filename_str = PyUnicode_DecodeFSDefault(filename);
200 if (filename_str == nullptr) {
201 PyErr_Print();
202 return -1;
203 }
204
205 PyCompilerFlags local_flags = _PyCompilerFlags_INIT;
206 if (flags == nullptr) {
207 flags = &local_flags;
208 }
209 // TODO(T46358395): Set sys.ps{1,2} in sys module if they don't exist
210 int err = 0;
211 int ret;
212 int nomem_count = 0;
213 do {
214 ret = PyRun_InteractiveOneObjectEx(fp, filename_str, flags);
215 if (ret == -1 && PyErr_Occurred()) {
216 // Prevent an endless loop after multiple consecutive MemoryErrors while
217 // still allowing an interactive command to fail with a MemoryError.
218 if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
219 if (++nomem_count > 16) {
220 PyErr_Clear();
221 err = -1;
222 break;
223 }
224 } else {
225 nomem_count = 0;
226 }
227 PyErr_Print();
228 flushStdFiles();
229 } else {
230 nomem_count = 0;
231 }
232 } while (ret != E_EOF);
233 Py_DECREF(filename_str);
234 return err;
235}
236
237static void setMainLoader(Thread* thread, Module& module, const char* filename,
238 SymbolId loader_name) {
239 Runtime* runtime = thread->runtime();
240 HandleScope scope(thread);
241 Str filename_str(&scope, runtime->newStrFromCStr(filename));
242 Str dunder_main_str(&scope, runtime->symbols()->at(ID(__main__)));
243 RawObject loader_obj =
244 thread->invokeFunction2(ID(_frozen_importlib_external), loader_name,
245 dunder_main_str, filename_str);
246 DCHECK(!loader_obj.isError(), "Unable to call file loader");
247 Object loader(&scope, loader_obj);
248 moduleAtPutById(thread, module, ID(__loader__), loader);
249}
250
251PY_EXPORT int PyRun_SimpleFile(FILE* fp, const char* filename) {
252 return PyRun_SimpleFileExFlags(fp, filename, /*closeit=*/0,
253 /*flags=*/nullptr);
254}
255
256PY_EXPORT int PyRun_SimpleFileEx(FILE* fp, const char* filename, int closeit) {
257 return PyRun_SimpleFileExFlags(fp, filename, closeit, /*flags=*/nullptr);
258}
259
260PY_EXPORT int PyRun_SimpleFileExFlags(FILE* fp, const char* filename,
261 int closeit, PyCompilerFlags* flags) {
262 Thread* thread = Thread::current();
263 Runtime* runtime = thread->runtime();
264 HandleScope scope(thread);
265
266 Object module_obj(&scope, runtime->findModuleById(ID(__main__)));
267 if (module_obj.isErrorNotFound()) {
268 Object name(&scope, runtime->symbols()->at(ID(__main__)));
269 module_obj = runtime->newModule(name);
270 Object modules(&scope, runtime->modules());
271 objectSetItem(thread, modules, name, module_obj);
272 }
273 Module module(&scope, *module_obj);
274
275 RawObject dunder_file = moduleAtById(thread, module, ID(__file__));
276 if (dunder_file.isErrorNotFound()) {
277 Str filename_str(&scope, runtime->newStrFromCStr(filename));
278 Object cached_obj(&scope, NoneType::object());
279 moduleAtPutById(thread, module, ID(__file__), filename_str);
280 moduleAtPutById(thread, module, ID(__cached__), cached_obj);
281 }
282
283 PyObject* result;
284 const char* extension = std::strrchr(filename, '.');
285 if (extension != nullptr && std::strcmp(extension, ".pyc") == 0) {
286 // Try to run a pyc file
287 setMainLoader(thread, module, filename, ID(SourcelessFileLoader));
288 result = runPycFile(fp, filename, module, flags);
289 } else {
290 // When running from stdin, leave __main__.__loader__ alone
291 if (std::strcmp(filename, "<stdin>") != 0) {
292 setMainLoader(thread, module, filename, ID(SourceFileLoader));
293 }
294 PyObject* module_proxy =
295 ApiHandle::borrowedReference(runtime, module.moduleProxy());
296 result = PyRun_FileExFlags(fp, filename, Py_file_input, module_proxy,
297 module_proxy, closeit, flags);
298 }
299 flushStdFiles();
300
301 int returncode;
302 if (result == nullptr) {
303 PyErr_Print();
304 returncode = -1;
305 } else {
306 Py_DECREF(result);
307 returncode = 0;
308 }
309
310 Str dunder_file_name(&scope, runtime->symbols()->at(ID(__file__)));
311 RawObject del_result =
312 moduleDeleteAttribute(thread, module, dunder_file_name);
313 if (del_result.isError()) {
314 PyErr_Clear();
315 }
316
317 return returncode;
318}
319
320PY_EXPORT int PyRun_SimpleString(const char* str) {
321 return PyRun_SimpleStringFlags(str, nullptr);
322}
323
324PY_EXPORT int PyRun_SimpleStringFlags(const char* str, PyCompilerFlags* flags) {
325 PyObject* module = PyImport_AddModule("__main__");
326 if (module == nullptr) return -1;
327 PyObject* module_proxy = PyModule_GetDict(module);
328 PyObject* result =
329 PyRun_StringFlags(str, Py_file_input, module_proxy, module_proxy, flags);
330 if (result == nullptr) {
331 PyErr_Print();
332 return -1;
333 }
334 Py_DECREF(result);
335 return 0;
336}
337
338PY_EXPORT void PyErr_Display(PyObject* /* exc */, PyObject* value,
339 PyObject* tb) {
340 Thread* thread = Thread::current();
341 HandleScope scope(thread);
342
343 DCHECK(value != nullptr, "value must be given");
344 Object value_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(value)));
345 Object tb_obj(&scope, tb ? ApiHandle::asObject(ApiHandle::fromPyObject(tb))
346 : NoneType::object());
347 if (displayException(thread, value_obj, tb_obj).isError()) {
348 // Don't propagate any exceptions that happened during printing. This isn't
349 // great, but it's necessary to match CPython.
350 thread->clearPendingException();
351 }
352}
353
354PY_EXPORT void PyErr_Print() { PyErr_PrintEx(1); }
355
356PY_EXPORT void PyErr_PrintEx(int set_sys_last_vars) {
357 Thread* thread = Thread::current();
358 if (set_sys_last_vars) {
359 printPendingExceptionWithSysLastVars(thread);
360 } else {
361 printPendingException(thread);
362 }
363}
364
365PY_EXPORT int PyOS_CheckStack() { UNIMPLEMENTED("PyOS_CheckStack"); }
366
367PY_EXPORT PyObject* PyRun_File(FILE* fp, const char* filename, int start,
368 PyObject* globals, PyObject* locals) {
369 return PyRun_FileExFlags(fp, filename, start, globals, locals,
370 /*closeit=*/0, /*flags=*/nullptr);
371}
372
373PY_EXPORT PyObject* PyRun_FileEx(FILE* fp, const char* filename, int start,
374 PyObject* globals, PyObject* locals,
375 int closeit) {
376 return PyRun_FileExFlags(fp, filename, start, globals, locals, closeit,
377 /*flags=*/nullptr);
378}
379
380PY_EXPORT PyObject* PyRun_FileExFlags(FILE* fp, const char* filename_cstr,
381 int start, PyObject* globals,
382 PyObject* locals, int closeit,
383 PyCompilerFlags* flags) {
384 word file_len;
385 unique_c_ptr<byte> buffer(OS::readFile(fp, &file_len));
386 if (closeit) std::fclose(fp);
387
388 Thread* thread = Thread::current();
389 Runtime* runtime = thread->runtime();
390 HandleScope scope(thread);
391
392 int iflags = flags != nullptr ? flags->cf_flags : 0;
393 // C-API uses this flag but it's an error for managed to pass it in
394 iflags &= ~PyCF_SOURCE_IS_UTF8;
395
396 View<byte> data(buffer.get(), file_len);
397 Object source(&scope, runtime->newBytesWithAll(data));
398 Str filename(&scope, runtime->newStrFromCStr(filename_cstr));
399 SymbolId mode_id;
400 if (start == Py_single_input) {
401 mode_id = ID(single);
402 } else if (start == Py_file_input) {
403 mode_id = ID(exec);
404 } else if (start == Py_eval_input) {
405 mode_id = ID(eval);
406 } else {
407 thread->raiseWithFmt(
408 LayoutId::kValueError,
409 "mode must be 'Py_single_input', 'Py_file_input' or 'Py_eval_input'");
410 return nullptr;
411 }
412 RawObject code =
413 compile(thread, source, filename, mode_id, iflags, Py_OptimizeFlag);
414 if (code.isError()) {
415 return nullptr;
416 }
417 Code code_code(&scope, code);
418 Object globals_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(globals)));
419 Object module_obj(&scope, NoneType::object());
420 if (globals_obj.isModuleProxy()) {
421 module_obj = ModuleProxy::cast(*globals_obj).module();
422 } else if (runtime->isInstanceOfDict(*globals_obj)) {
423 UNIMPLEMENTED("User-defined globals is unsupported");
424 } else {
425 thread->raiseBadInternalCall();
426 return nullptr;
427 }
428 Object implicit_globals(&scope, NoneType::object());
429 if (locals != nullptr && globals != locals) {
430 implicit_globals = ApiHandle::asObject(ApiHandle::fromPyObject(locals));
431 if (!runtime->isMapping(thread, implicit_globals)) {
432 thread->raiseBadInternalCall();
433 return nullptr;
434 }
435 }
436 Module module(&scope, *module_obj);
437 RawObject result = thread->exec(code_code, module, implicit_globals);
438 return result.isError() ? nullptr : ApiHandle::newReference(runtime, result);
439}
440
441PY_EXPORT PyObject* PyRun_FileFlags(FILE* fp, const char* filename, int start,
442 PyObject* globals, PyObject* locals,
443 PyCompilerFlags* flags) {
444 return PyRun_FileExFlags(fp, filename, start, globals, locals,
445 /*closeit=*/0, flags);
446}
447
448PY_EXPORT PyObject* PyRun_String(const char* str, int start, PyObject* globals,
449 PyObject* locals) {
450 return PyRun_StringFlags(str, start, globals, locals, /*flags=*/nullptr);
451}
452
453PY_EXPORT PyObject* PyRun_StringFlags(const char* str, int start,
454 PyObject* globals, PyObject* locals,
455 PyCompilerFlags* flags) {
456 Thread* thread = Thread::current();
457 PyObject* filename = ApiHandle::borrowedReference(
458 thread->runtime(), Runtime::internStrFromCStr(thread, "<string>"));
459
460 PyArena* arena = PyArena_New();
461 if (arena == nullptr) return nullptr;
462
463 struct _mod* mod =
464 PyParser_ASTFromStringObject(str, filename, start, flags, arena);
465 PyObject* ret = nullptr;
466 if (mod != nullptr) {
467 ret = runMod(mod, filename, globals, locals, flags, arena);
468 }
469 PyArena_Free(arena);
470 return ret;
471}
472
473} // namespace py