this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "sys-module.h"
3
4#include <unistd.h>
5
6#include <cerrno>
7#include <cstdio>
8#include <cstring>
9
10#include "cpython-types.h"
11
12#include "builtins-module.h"
13#include "builtins.h"
14#include "bytes-builtins.h"
15#include "capi.h"
16#include "dict-builtins.h"
17#include "exception-builtins.h"
18#include "file.h"
19#include "frame.h"
20#include "frozen-modules.h"
21#include "globals.h"
22#include "handles.h"
23#include "int-builtins.h"
24#include "module-builtins.h"
25#include "modules.h"
26#include "objects.h"
27#include "os.h"
28#include "runtime.h"
29#include "str-builtins.h"
30#include "thread.h"
31#include "version.h"
32
33namespace py {
34
35void FUNC(sys, __init_module__)(Thread* thread, const Module& module,
36 View<byte> bytecode) {
37 HandleScope scope(thread);
38 Runtime* runtime = thread->runtime();
39 Object modules(&scope, runtime->modules());
40 moduleAtPutById(thread, module, ID(modules), modules);
41
42 // Fill in sys...
43 Object platform(&scope, runtime->newStrFromCStr(OS::name()));
44 moduleAtPutById(thread, module, ID(platform), platform);
45
46 Object stderr_fd_val(&scope, SmallInt::fromWord(File::kStderr));
47 moduleAtPutById(thread, module, ID(_stderr_fd), stderr_fd_val);
48 Object stdin_fd_val(&scope, SmallInt::fromWord(File::kStdin));
49 moduleAtPutById(thread, module, ID(_stdin_fd), stdin_fd_val);
50 Object stdout_fd_val(&scope, SmallInt::fromWord(File::kStdout));
51 moduleAtPutById(thread, module, ID(_stdout_fd), stdout_fd_val);
52
53 Object byteorder(
54 &scope,
55 SmallStr::fromCStr(endian::native == endian::little ? "little" : "big"));
56 moduleAtPutById(thread, module, ID(byteorder), byteorder);
57
58 // maxsize is defined as the largest supported length of containers which
59 // would be `SmallInt::kMaxValue`. However in practice it is used to
60 // determine the size of a machine word which is kMaxWord.
61 Object maxsize(&scope, runtime->newInt(kMaxWord));
62 moduleAtPutById(thread, module, ID(maxsize), maxsize);
63
64 // Count the number of builtin modules and create a tuple
65 uword num_extension_modules = 0;
66 while (PyImport_Inittab[num_extension_modules].name != nullptr) {
67 num_extension_modules++;
68 }
69 word num_builtin_modules = kNumFrozenModules + num_extension_modules;
70 MutableTuple builtin_module_names(
71 &scope, runtime->newMutableTuple(num_builtin_modules));
72 for (word i = 0; i < kNumFrozenModules; i++) {
73 builtin_module_names.atPut(
74 i, Runtime::internStrFromCStr(thread, kFrozenModules[i].name));
75 }
76 for (int i = 0; PyImport_Inittab[i].name != nullptr; i++) {
77 builtin_module_names.atPut(
78 kNumFrozenModules + i,
79 Runtime::internStrFromCStr(thread, PyImport_Inittab[i].name));
80 }
81 Tuple builtin_module_names_tuple(&scope,
82 builtin_module_names.becomeImmutable());
83 moduleAtPutById(thread, module, ID(builtin_module_names),
84 builtin_module_names_tuple);
85
86 // Fill in version-related fields.
87 Int hexversion(&scope, SmallInt::fromWord(kVersionHex));
88 moduleAtPutById(thread, module, ID(hexversion), hexversion);
89 Str version(&scope, runtime->newStrFromCStr(kVersionInfo));
90 moduleAtPutById(thread, module, ID(version), version);
91 Object release_level(&scope, runtime->newStrFromCStr(kReleaseLevel));
92 moduleAtPutById(thread, module, ID(_version_releaselevel), release_level);
93
94 Object buffered_stdio(&scope, Bool::fromBool(runtime->useBufferedStdio()));
95 moduleAtPutById(thread, module, ID(_use_buffered_stdio), buffered_stdio);
96
97 executeFrozenModule(thread, module, bytecode);
98
99 // Fill in hash_info.
100 Object hash_width(&scope, SmallInt::fromWord(SmallInt::kBits));
101 Object hash_modulus(&scope, SmallInt::fromWord(kArithmeticHashModulus));
102 Object hash_inf(&scope, SmallInt::fromWord(kHashInf));
103 Object hash_nan(&scope, SmallInt::fromWord(kHashNan));
104 Object hash_imag(&scope, SmallInt::fromWord(kHashImag));
105 Object hash_algorithm(&scope, runtime->symbols()->at(ID(siphash24)));
106 Object hash_bits(&scope, SmallInt::fromWord(64));
107 Object hash_seed_bits(&scope, SmallInt::fromWord(128));
108 Object hash_cutoff(&scope, SmallInt::fromWord(SmallStr::kMaxLength));
109 Tuple hash_info_data(&scope, runtime->newTupleWithN(
110 9, &hash_width, &hash_modulus, &hash_inf,
111 &hash_nan, &hash_imag, &hash_algorithm,
112 &hash_bits, &hash_seed_bits, &hash_cutoff));
113 Object hash_info(
114 &scope, thread->invokeFunction1(ID(sys), ID(_HashInfo), hash_info_data));
115 moduleAtPutById(thread, module, ID(hash_info), hash_info);
116
117 runtime->cacheSysInstances(thread, module);
118}
119
120int flushStdFiles() {
121 Thread* thread = Thread::current();
122 HandleScope scope(thread);
123 int return_value = 0;
124
125 // PyErr_Fetch
126 Object exc(&scope, thread->pendingExceptionType());
127 Object val(&scope, thread->pendingExceptionValue());
128 Object tb(&scope, thread->pendingExceptionTraceback());
129 thread->clearPendingException();
130
131 Runtime* runtime = thread->runtime();
132 Module sys(&scope, runtime->findModuleById(ID(sys)));
133 Object stdout_obj(&scope, moduleAtById(thread, sys, ID(stdout)));
134 if (!stdout_obj.isErrorNotFound()) {
135 if (thread->invokeMethod1(stdout_obj, ID(flush)).isErrorException()) {
136 thread->clearPendingException();
137 return_value = -1;
138 }
139 }
140 Object stderr_obj(&scope, moduleAtById(thread, sys, ID(stderr)));
141 if (!stderr_obj.isErrorNotFound()) {
142 if (thread->invokeMethod1(stderr_obj, ID(flush)).isErrorException()) {
143 thread->clearPendingException();
144 return_value = -1;
145 }
146 }
147
148 // PyErr_Restore
149 thread->setPendingExceptionType(*exc);
150 thread->setPendingExceptionValue(*val);
151 thread->setPendingExceptionTraceback(*tb);
152 return return_value;
153}
154
155void initializeRuntimePaths(Thread* thread) {
156 HandleScope scope(thread);
157 Object result(&scope, thread->invokeFunction0(ID(sys), ID(_calculate_path)));
158 if (result.isError()) {
159 thread->clearPendingException();
160 thread->raiseBadInternalCall();
161 return;
162 }
163 CHECK(result.isTuple(), "sys._calculate_path must return tuple");
164 Tuple paths(&scope, *result);
165
166 Str prefix(&scope, paths.at(0));
167 word prefix_codepoints = prefix.codePointLength();
168 std::unique_ptr<wchar_t[]> prefix_wstr(new wchar_t[prefix_codepoints + 1]);
169 strCopyToWCStr(prefix_wstr.get(), prefix_codepoints + 1, prefix);
170 Runtime::setPrefix(prefix_wstr.get());
171
172 Str exec_prefix(&scope, paths.at(1));
173 word exec_prefix_codepoints = exec_prefix.codePointLength();
174 std::unique_ptr<wchar_t[]> exec_prefix_wstr(
175 new wchar_t[exec_prefix_codepoints + 1]);
176 strCopyToWCStr(exec_prefix_wstr.get(), exec_prefix_codepoints + 1,
177 exec_prefix);
178 Runtime::setExecPrefix(exec_prefix_wstr.get());
179
180 Str module_search_path(&scope, paths.at(2));
181 word module_search_path_codepoints = module_search_path.codePointLength();
182 std::unique_ptr<wchar_t[]> module_search_path_wstr(
183 new wchar_t[module_search_path_codepoints + 1]);
184 strCopyToWCStr(module_search_path_wstr.get(),
185 module_search_path_codepoints + 1, module_search_path);
186 Runtime::setModuleSearchPath(module_search_path_wstr.get());
187}
188
189RawObject initializeSys(Thread* thread, const Str& executable,
190 const List& python_path, const Tuple& flags_data,
191 const List& warnoptions,
192 bool extend_python_path_with_stdlib) {
193 HandleScope scope(thread);
194 Object extend_python_path_with_stdlib_obj(
195 &scope, Bool::fromBool(extend_python_path_with_stdlib));
196 return thread->invokeFunction5(ID(sys), ID(_init), executable, python_path,
197 flags_data, warnoptions,
198 extend_python_path_with_stdlib_obj);
199}
200
201void setPycachePrefix(Thread* thread, const Object& pycache_prefix) {
202 HandleScope scope(thread);
203 Runtime* runtime = thread->runtime();
204 Module module(&scope, runtime->findModuleById(ID(sys)));
205 moduleAtPutById(thread, module, ID(pycache_prefix), pycache_prefix);
206}
207
208static void writeImpl(Thread* thread, const Object& file, FILE* fallback_fp,
209 const char* format, va_list va) {
210 HandleScope scope(thread);
211 Object type(&scope, thread->pendingExceptionType());
212 Object value(&scope, thread->pendingExceptionValue());
213 Object tb(&scope, thread->pendingExceptionTraceback());
214 thread->clearPendingException();
215
216 static const char truncated[] = "... truncated";
217 static constexpr int message_size = 1001;
218 char buffer[message_size + sizeof(truncated) - 1];
219 int written = std::vsnprintf(buffer, message_size, format, va);
220 CHECK(written >= 0, "vsnprintf failed");
221 if (written >= message_size) {
222 std::memcpy(&buffer[message_size - 1], truncated, sizeof(truncated));
223 written = message_size + sizeof(truncated) - 2;
224 }
225 Str str(&scope, thread->runtime()->newStrWithAll(
226 View<byte>(reinterpret_cast<byte*>(buffer), written)));
227 if (file.isNoneType() ||
228 thread->invokeMethod2(file, ID(write), str).isError()) {
229 fwrite(buffer, 1, written, fallback_fp);
230 }
231
232 thread->clearPendingException();
233 thread->setPendingExceptionType(*type);
234 thread->setPendingExceptionValue(*value);
235 thread->setPendingExceptionTraceback(*tb);
236}
237
238void writeStdout(Thread* thread, const char* format, ...) {
239 va_list va;
240 va_start(va, format);
241 writeStdoutV(thread, format, va);
242 va_end(va);
243}
244
245void writeStdoutV(Thread* thread, const char* format, va_list va) {
246 HandleScope scope(thread);
247 ValueCell sys_stdout_cell(&scope, thread->runtime()->sysStdout());
248 Object sys_stdout(&scope, NoneType::object());
249 if (!sys_stdout_cell.isUnbound()) {
250 sys_stdout = sys_stdout_cell.value();
251 }
252 writeImpl(thread, sys_stdout, stdout, format, va);
253}
254
255void writeStderr(Thread* thread, const char* format, ...) {
256 va_list va;
257 va_start(va, format);
258 writeStderrV(thread, format, va);
259 va_end(va);
260}
261
262void writeStderrV(Thread* thread, const char* format, va_list va) {
263 HandleScope scope(thread);
264 ValueCell sys_stderr_cell(&scope, thread->runtime()->sysStderr());
265 Object sys_stderr(&scope, NoneType::object());
266 if (!sys_stderr_cell.isUnbound()) {
267 sys_stderr = sys_stderr_cell.value();
268 }
269 writeImpl(thread, sys_stderr, stderr, format, va);
270}
271
272RawObject FUNC(sys, _getframe)(Thread* thread, Arguments args) {
273 HandleScope scope(thread);
274 Runtime* runtime = thread->runtime();
275 Object depth_obj(&scope, args.get(0));
276 if (!runtime->isInstanceOfInt(*depth_obj)) {
277 return thread->raiseRequiresType(depth_obj, ID(int));
278 }
279 word depth = intUnderlying(*depth_obj).asWordSaturated();
280 if (depth < 0) {
281 depth = 0;
282 }
283 // Increment the requested depth to skip the frame for sys._getframe itself.
284 // TODO(T64005113): This should be deleted.
285 depth++;
286 Object result(&scope, thread->heapFrameAtDepth(depth));
287 if (result.isNoneType()) {
288 return thread->raiseWithFmt(LayoutId::kValueError,
289 "call stack is not deep enough");
290 }
291 return *result;
292}
293
294RawObject FUNC(sys, _program_name)(Thread* thread, Arguments) {
295 return newStrFromWideChar(thread, Runtime::programName());
296}
297
298RawObject FUNC(sys, excepthook)(Thread* thread, Arguments args) {
299 HandleScope scope(thread);
300 // type argument is ignored
301 Object value(&scope, args.get(1));
302 Object tb(&scope, args.get(2));
303 return displayException(thread, value, tb);
304}
305
306RawObject FUNC(sys, exc_info)(Thread* thread, Arguments) {
307 HandleScope scope(thread);
308 Object caught_exc_state_obj(&scope, thread->topmostCaughtExceptionState());
309 if (caught_exc_state_obj.isNoneType()) {
310 Object type(&scope, NoneType::object());
311 Object value(&scope, NoneType::object());
312 Object traceback(&scope, NoneType::object());
313 return thread->runtime()->newTupleWith3(type, value, traceback);
314 }
315 ExceptionState caught_exc_state(&scope, *caught_exc_state_obj);
316 Object type(&scope, caught_exc_state.type());
317 Object value(&scope, caught_exc_state.value());
318 Object traceback(&scope, caught_exc_state.traceback());
319 return thread->runtime()->newTupleWith3(type, value, traceback);
320}
321
322RawObject FUNC(sys, intern)(Thread* thread, Arguments args) {
323 HandleScope scope(thread);
324 Object string(&scope, args.get(0));
325 if (!thread->runtime()->isInstanceOfStr(*string)) {
326 return thread->raiseRequiresType(string, ID(str));
327 }
328 if (!string.isStr()) {
329 return thread->raiseWithFmt(LayoutId::kTypeError, "can't intern %T",
330 &string);
331 }
332 return Runtime::internStr(thread, string);
333}
334
335RawObject FUNC(sys, getrecursionlimit)(Thread* thread, Arguments) {
336 return thread->runtime()->newInt(thread->recursionLimit());
337}
338
339RawObject FUNC(sys, is_finalizing)(Thread* thread, Arguments) {
340 return Bool::fromBool(thread->runtime()->isFinalizing());
341}
342
343RawObject FUNC(sys, setrecursionlimit)(Thread* thread, Arguments args) {
344 HandleScope scope(thread);
345 Int limit(&scope, args.get(0));
346 OptInt<int> opt_val = limit.asInt<int>();
347 if (opt_val.error != CastError::None) {
348 return thread->raiseWithFmt(LayoutId::kOverflowError,
349 "Python int too large to convert to C int");
350 }
351
352 // TODO(T62600497) Raise RecursionError if new limit is too low at current
353 // recursion depth
354
355 thread->setRecursionLimit(opt_val.value);
356 return NoneType::object();
357}
358
359RawObject FUNC(sys, set_asyncgen_hooks)(Thread* thread, Arguments args) {
360 HandleScope scope(thread);
361 Object finalizer(&scope, args.get(1));
362 Runtime* runtime = thread->runtime();
363 Object first_iter(&scope, args.get(0));
364 if (!first_iter.isUnbound()) {
365 if (!first_iter.isNoneType() && !runtime->isCallable(thread, first_iter)) {
366 return thread->raiseWithFmt(LayoutId::kTypeError,
367 "callable firstiter expected, got %T",
368 &first_iter);
369 }
370 thread->setAsyncgenHooksFirstIter(*first_iter);
371 }
372 if (!finalizer.isUnbound()) {
373 if (!finalizer.isNoneType() && !runtime->isCallable(thread, finalizer)) {
374 return thread->raiseWithFmt(LayoutId::kTypeError,
375 "callable finalizer expected, got %T",
376 &finalizer);
377 }
378 thread->setAsyncgenHooksFinalizer(*finalizer);
379 }
380 return NoneType::object();
381}
382
383} // namespace py