this repo has no description
at trunk 483 lines 13 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <cstdarg> 3#include <cwchar> 4 5#include "cpython-data.h" 6#include "cpython-types.h" 7 8#include "api-handle.h" 9#include "handles.h" 10#include "modsupport-internal.h" 11#include "module-builtins.h" 12#include "objects.h" 13#include "runtime.h" 14 15namespace py { 16 17PY_EXPORT int PyModule_AddObject(PyObject* pymodule, const char* name, 18 PyObject* obj) { 19 Thread* thread = Thread::current(); 20 HandleScope scope(thread); 21 Runtime* runtime = thread->runtime(); 22 23 Object module_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pymodule))); 24 if (!runtime->isInstanceOfModule(*module_obj)) { 25 thread->raiseWithFmt(LayoutId::kTypeError, 26 "PyModule_AddObject() needs module as first arg"); 27 return -1; 28 } 29 if (name == nullptr) { 30 // TODO(cshapiro): throw a TypeError 31 return -1; 32 } 33 Object name_obj(&scope, Runtime::internStrFromCStr(thread, name)); 34 Module module(&scope, *module_obj); 35 Object value(&scope, ApiHandle::stealReference(obj)); 36 moduleAtPut(thread, module, name_obj, value); 37 return 0; 38} 39 40PY_EXPORT int PyModule_AddIntConstant(PyObject* m, const char* name, 41 long value) { 42 PyObject* o = PyLong_FromLong(value); 43 if (!o) return -1; 44 if (PyModule_AddObject(m, name, o) == 0) return 0; 45 Py_DECREF(o); 46 return -1; 47} 48 49PY_EXPORT int PyModule_AddStringConstant(PyObject* pymodule, const char* name, 50 const char* value) { 51 PyObject* str = PyUnicode_FromString(value); 52 if (!str) return -1; 53 if (PyModule_AddObject(pymodule, name, str) == 0) return 0; 54 Py_DECREF(str); 55 return -1; 56} 57 58static PyObject* doMakeTuple(const char**, std::va_list*, char, Py_ssize_t, 59 int); 60static PyObject* doMakeList(const char**, std::va_list*, char, Py_ssize_t, int); 61static PyObject* doMakeDict(const char**, std::va_list*, char, Py_ssize_t, int); 62 63static void doIgnore(const char** p_format, std::va_list* p_va, char endchar, 64 Py_ssize_t n, int flags) { 65 DCHECK(PyErr_Occurred() != nullptr, "exception has not been raised"); 66 PyObject* v = PyTuple_New(n); 67 for (Py_ssize_t i = 0; i < n; i++) { 68 PyObject *exception, *value, *tb; 69 PyErr_Fetch(&exception, &value, &tb); 70 PyObject* w = makeValueFromFormat(p_format, p_va, flags); 71 PyErr_Restore(exception, value, tb); 72 if (w != nullptr) { 73 if (v != nullptr) { 74 PyTuple_SET_ITEM(v, i, w); 75 } else { 76 Py_DECREF(w); 77 } 78 } 79 } 80 Py_XDECREF(v); 81 if (**p_format != endchar) { 82 Thread::current()->raiseWithFmt(LayoutId::kSystemError, 83 "Unmatched paren in format"); 84 return; 85 } 86 if (endchar != '\0') { 87 ++*p_format; 88 } 89} 90 91static PyObject* doMakeDict(const char** p_format, std::va_list* p_va, 92 char endchar, Py_ssize_t n, int flags) { 93 if (n < 0) { 94 return nullptr; 95 } 96 if (n % 2) { 97 Thread::current()->raiseWithFmt(LayoutId::kSystemError, "Bad dict format"); 98 doIgnore(p_format, p_va, endchar, n, flags); 99 return nullptr; 100 } 101 // Note that we can't bail immediately on error as this will leak refcounts on 102 // any 'N' arguments. 103 PyObject* d = PyDict_New(); 104 if (d == nullptr) { 105 doIgnore(p_format, p_va, endchar, n, flags); 106 return nullptr; 107 } 108 for (Py_ssize_t i = 0; i < n; i += 2) { 109 PyObject* k = makeValueFromFormat(p_format, p_va, flags); 110 if (k == nullptr) { 111 doIgnore(p_format, p_va, endchar, n - i - 1, flags); 112 Py_DECREF(d); 113 return nullptr; 114 } 115 PyObject* v = makeValueFromFormat(p_format, p_va, flags); 116 if (v == nullptr || PyDict_SetItem(d, k, v) < 0) { 117 doIgnore(p_format, p_va, endchar, n - i - 2, flags); 118 Py_DECREF(k); 119 Py_XDECREF(v); 120 Py_DECREF(d); 121 return nullptr; 122 } 123 Py_DECREF(k); 124 Py_DECREF(v); 125 } 126 if (**p_format != endchar) { 127 Py_DECREF(d); 128 Thread::current()->raiseWithFmt(LayoutId::kSystemError, 129 "Unmatched paren in format"); 130 return nullptr; 131 } 132 if (endchar != '\0') { 133 ++*p_format; 134 } 135 return d; 136} 137 138static PyObject* doMakeList(const char** p_format, std::va_list* p_va, 139 char endchar, Py_ssize_t n, int flags) { 140 if (n < 0) { 141 return nullptr; 142 } 143 // Note that we can't bail immediately on error as this will leak refcounts on 144 // any 'N' arguments. 145 PyObject* v = PyList_New(n); 146 if (v == nullptr) { 147 doIgnore(p_format, p_va, endchar, n, flags); 148 return nullptr; 149 } 150 for (Py_ssize_t i = 0; i < n; i++) { 151 PyObject* w = makeValueFromFormat(p_format, p_va, flags); 152 if (w == nullptr) { 153 doIgnore(p_format, p_va, endchar, n - i - 1, flags); 154 Py_DECREF(v); 155 return nullptr; 156 } 157 PyList_SetItem(v, i, w); 158 } 159 if (**p_format != endchar) { 160 Py_DECREF(v); 161 Thread::current()->raiseWithFmt(LayoutId::kSystemError, 162 "Unmatched paren in format"); 163 return nullptr; 164 } 165 if (endchar != '\0') { 166 ++*p_format; 167 } 168 return v; 169} 170 171static PyObject* doMakeTuple(const char** p_format, std::va_list* p_va, 172 char endchar, Py_ssize_t n, int flags) { 173 if (n < 0) { 174 return nullptr; 175 } 176 // Note that we can't bail immediately on error as this will leak refcounts on 177 // any 'N' arguments. 178 PyObject* v = PyTuple_New(n); 179 if (v == nullptr) { 180 doIgnore(p_format, p_va, endchar, n, flags); 181 return nullptr; 182 } 183 for (Py_ssize_t i = 0; i < n; i++) { 184 PyObject* w = makeValueFromFormat(p_format, p_va, flags); 185 if (w == nullptr) { 186 doIgnore(p_format, p_va, endchar, n - i - 1, flags); 187 Py_DECREF(v); 188 return nullptr; 189 } 190 PyTuple_SET_ITEM(v, i, w); 191 } 192 if (**p_format != endchar) { 193 Py_DECREF(v); 194 Thread::current()->raiseWithFmt(LayoutId::kSystemError, 195 "Unmatched paren in format"); 196 return nullptr; 197 } 198 if (endchar != '\0') { 199 ++*p_format; 200 } 201 return v; 202} 203 204Py_ssize_t countFormat(const char* format, char endchar) { 205 Py_ssize_t count = 0; 206 int level = 0; 207 while (level > 0 || *format != endchar) { 208 switch (*format) { 209 case '\0': 210 // Premature end 211 Thread::current()->raiseWithFmt(LayoutId::kSystemError, 212 "unmatched paren in format"); 213 return -1; 214 case '(': 215 case '[': 216 case '{': 217 if (level == 0) { 218 count++; 219 } 220 level++; 221 break; 222 case ')': 223 case ']': 224 case '}': 225 level--; 226 break; 227 case '#': 228 case '&': 229 case ',': 230 case ':': 231 case ' ': 232 case '\t': 233 break; 234 default: 235 if (level == 0) { 236 count++; 237 } 238 } 239 format++; 240 } 241 return count; 242} 243 244PyObject* makeValueFromFormat(const char** p_format, std::va_list* p_va, 245 int flags) { 246 for (;;) { 247 switch (*(*p_format)++) { 248 case '(': 249 return doMakeTuple(p_format, p_va, ')', countFormat(*p_format, ')'), 250 flags); 251 252 case '[': 253 return doMakeList(p_format, p_va, ']', countFormat(*p_format, ']'), 254 flags); 255 256 case '{': 257 return doMakeDict(p_format, p_va, '}', countFormat(*p_format, '}'), 258 flags); 259 260 case 'b': 261 case 'B': 262 case 'h': 263 case 'i': 264 return PyLong_FromLong(va_arg(*p_va, int)); 265 266 case 'H': 267 return PyLong_FromLong(va_arg(*p_va, unsigned int)); 268 269 case 'I': 270 return PyLong_FromUnsignedLong(va_arg(*p_va, unsigned int)); 271 272 case 'n': 273 if (sizeof(size_t) != sizeof(long)) { 274 return PyLong_FromSsize_t(va_arg(*p_va, Py_ssize_t)); 275 } 276 FALLTHROUGH; 277 case 'l': 278 return PyLong_FromLong(va_arg(*p_va, long)); 279 280 case 'k': { 281 return PyLong_FromUnsignedLong(va_arg(*p_va, unsigned long)); 282 } 283 284 case 'L': 285 return PyLong_FromLongLong(va_arg(*p_va, long long)); 286 287 case 'K': 288 return PyLong_FromUnsignedLongLong(va_arg(*p_va, unsigned long long)); 289 290 case 'u': { 291 Py_UNICODE* u = va_arg(*p_va, Py_UNICODE*); 292 Py_ssize_t n; 293 if (**p_format == '#') { 294 ++*p_format; 295 if (flags & kFlagSizeT) { 296 n = va_arg(*p_va, Py_ssize_t); 297 } else { 298 n = va_arg(*p_va, int); 299 } 300 } else { 301 n = -1; 302 } 303 PyObject* v; 304 if (u == nullptr) { 305 v = Py_None; 306 Py_INCREF(v); 307 } else { 308 if (n < 0) { 309 n = std::wcslen(u); 310 } 311 v = PyUnicode_FromWideChar(u, n); 312 } 313 return v; 314 } 315 case 'f': 316 case 'd': 317 return PyFloat_FromDouble(va_arg(*p_va, double)); 318 319 case 'D': 320 return PyComplex_FromCComplex(*va_arg(*p_va, Py_complex*)); 321 322 case 'c': { 323 char ch = va_arg(*p_va, int); 324 return PyBytes_FromStringAndSize(&ch, 1); 325 } 326 case 'C': { 327 int i = va_arg(*p_va, int); 328 return PyUnicode_FromOrdinal(i); 329 } 330 331 case 's': 332 case 'z': 333 case 'U': { // XXX deprecated alias 334 const char* str = va_arg(*p_va, const char*); 335 Py_ssize_t n; 336 if (**p_format == '#') { 337 ++*p_format; 338 if (flags & kFlagSizeT) { 339 n = va_arg(*p_va, Py_ssize_t); 340 } else { 341 n = va_arg(*p_va, int); 342 } 343 } else { 344 n = -1; 345 } 346 PyObject* v; 347 if (str == nullptr) { 348 v = Py_None; 349 Py_INCREF(v); 350 } else { 351 if (n < 0) { 352 size_t m = std::strlen(str); 353 if (m > kMaxWord) { 354 Thread::current()->raiseWithFmt( 355 LayoutId::kOverflowError, 356 "string too long for Python string"); 357 return nullptr; 358 } 359 n = static_cast<Py_ssize_t>(m); 360 } 361 v = PyUnicode_FromStringAndSize(str, n); 362 } 363 return v; 364 } 365 366 case 'y': { 367 PyObject* v; 368 const char* str = va_arg(*p_va, const char*); 369 Py_ssize_t n; 370 if (**p_format == '#') { 371 ++*p_format; 372 if (flags & kFlagSizeT) { 373 n = va_arg(*p_va, Py_ssize_t); 374 } else { 375 n = va_arg(*p_va, int); 376 } 377 } else { 378 n = -1; 379 } 380 if (str == nullptr) { 381 v = Py_None; 382 Py_INCREF(v); 383 } else { 384 if (n < 0) { 385 size_t m = std::strlen(str); 386 if (m > kMaxWord) { 387 Thread::current()->raiseWithFmt( 388 LayoutId::kOverflowError, "string too long for Python bytes"); 389 return nullptr; 390 } 391 n = static_cast<Py_ssize_t>(m); 392 } 393 v = PyBytes_FromStringAndSize(str, n); 394 } 395 return v; 396 } 397 398 case 'N': 399 case 'S': 400 case 'O': 401 if (**p_format == '&') { 402 typedef PyObject* (*converter)(void*); 403 converter func = va_arg(*p_va, converter); 404 void* arg = va_arg(*p_va, void*); 405 ++*p_format; 406 return (*func)(arg); 407 } else { 408 PyObject* v = va_arg(*p_va, PyObject*); 409 if (v != nullptr) { 410 if (*(*p_format - 1) != 'N') Py_INCREF(v); 411 } else if (!PyErr_Occurred()) { 412 // If a NULL was passed because a call that should have constructed 413 // a value failed, that's OK, and we pass the error on; but if no 414 // error occurred it's not clear that the caller knew what she was 415 // doing. 416 Thread::current()->raiseWithFmt( 417 LayoutId::kSystemError, "NULL object passed to Py_BuildValue"); 418 } 419 return v; 420 } 421 422 case ':': 423 case ',': 424 case ' ': 425 case '\t': 426 break; 427 428 default: 429 Thread::current()->raiseWithFmt( 430 LayoutId::kSystemError, "bad format char passed to Py_BuildValue"); 431 return nullptr; 432 } 433 } 434} 435 436static PyObject* vaBuildValue(const char* format, std::va_list va, int flags) { 437 Py_ssize_t n = countFormat(format, '\0'); 438 if (n < 0) { 439 return nullptr; 440 } 441 if (n == 0) { 442 Py_INCREF(Py_None); 443 return Py_None; 444 } 445 std::va_list lva; 446 va_copy(lva, va); 447 const char* f = format; 448 PyObject* retval; 449 if (n == 1) { 450 retval = makeValueFromFormat(&f, &lva, flags); 451 } else { 452 retval = doMakeTuple(&f, &lva, '\0', n, flags); 453 } 454 va_end(lva); 455 return retval; 456} 457 458PY_EXPORT PyObject* Py_VaBuildValue(const char* format, std::va_list va) { 459 return vaBuildValue(format, va, 0); 460} 461 462PY_EXPORT PyObject* _Py_VaBuildValue_SizeT(const char* format, 463 std::va_list va) { 464 return vaBuildValue(format, va, kFlagSizeT); 465} 466 467PY_EXPORT PyObject* Py_BuildValue(const char* format, ...) { 468 std::va_list va; 469 va_start(va, format); 470 PyObject* retval = vaBuildValue(format, va, 0); 471 va_end(va); 472 return retval; 473} 474 475PY_EXPORT PyObject* _Py_BuildValue_SizeT(const char* format, ...) { 476 std::va_list va; 477 va_start(va, format); 478 PyObject* retval = vaBuildValue(format, va, kFlagSizeT); 479 va_end(va); 480 return retval; 481} 482 483} // namespace py