exc_ops.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // Exception related primitive operations
  2. //
  3. // These are registered in mypyc.primitives.exc_ops.
  4. #include <Python.h>
  5. #include "CPy.h"
  6. void CPy_Raise(PyObject *exc) {
  7. if (PyObject_IsInstance(exc, (PyObject *)&PyType_Type)) {
  8. PyObject *obj = PyObject_CallNoArgs(exc);
  9. if (!obj)
  10. return;
  11. PyErr_SetObject(exc, obj);
  12. Py_DECREF(obj);
  13. } else {
  14. PyErr_SetObject((PyObject *)Py_TYPE(exc), exc);
  15. }
  16. }
  17. void CPy_Reraise(void) {
  18. PyObject *p_type, *p_value, *p_traceback;
  19. PyErr_GetExcInfo(&p_type, &p_value, &p_traceback);
  20. PyErr_Restore(p_type, p_value, p_traceback);
  21. }
  22. void CPyErr_SetObjectAndTraceback(PyObject *type, PyObject *value, PyObject *traceback) {
  23. if (!PyType_Check(type) && value == Py_None) {
  24. // The first argument must be an exception instance
  25. value = type;
  26. type = (PyObject *)Py_TYPE(value);
  27. }
  28. // Set the value and traceback of an error. Because calling
  29. // PyErr_Restore takes away a reference to each object passed in
  30. // as an argument, we manually increase the reference count of
  31. // each argument before calling it.
  32. Py_INCREF(type);
  33. Py_INCREF(value);
  34. Py_INCREF(traceback);
  35. PyErr_Restore(type, value, traceback);
  36. }
  37. tuple_T3OOO CPy_CatchError(void) {
  38. // We need to return the existing sys.exc_info() information, so
  39. // that it can be restored when we finish handling the error we
  40. // are catching now. Grab that triple and convert NULL values to
  41. // the ExcDummy object in order to simplify refcount handling in
  42. // generated code.
  43. tuple_T3OOO ret;
  44. PyErr_GetExcInfo(&ret.f0, &ret.f1, &ret.f2);
  45. _CPy_ToDummy(&ret.f0);
  46. _CPy_ToDummy(&ret.f1);
  47. _CPy_ToDummy(&ret.f2);
  48. if (!PyErr_Occurred()) {
  49. PyErr_SetString(PyExc_RuntimeError, "CPy_CatchError called with no error!");
  50. }
  51. // Retrieve the error info and normalize it so that it looks like
  52. // what python code needs it to be.
  53. PyObject *type, *value, *traceback;
  54. PyErr_Fetch(&type, &value, &traceback);
  55. // Could we avoid always normalizing?
  56. PyErr_NormalizeException(&type, &value, &traceback);
  57. if (traceback != NULL) {
  58. PyException_SetTraceback(value, traceback);
  59. }
  60. // Indicate that we are now handling this exception by stashing it
  61. // in sys.exc_info(). mypyc routines that need access to the
  62. // exception will read it out of there.
  63. PyErr_SetExcInfo(type, value, traceback);
  64. // Clear the error indicator, since the exception isn't
  65. // propagating anymore.
  66. PyErr_Clear();
  67. return ret;
  68. }
  69. void CPy_RestoreExcInfo(tuple_T3OOO info) {
  70. PyErr_SetExcInfo(_CPy_FromDummy(info.f0), _CPy_FromDummy(info.f1), _CPy_FromDummy(info.f2));
  71. }
  72. bool CPy_ExceptionMatches(PyObject *type) {
  73. return PyErr_GivenExceptionMatches((PyObject *)Py_TYPE(CPy_ExcState()->exc_value), type);
  74. }
  75. PyObject *CPy_GetExcValue(void) {
  76. PyObject *exc = CPy_ExcState()->exc_value;
  77. Py_INCREF(exc);
  78. return exc;
  79. }
  80. static inline void _CPy_ToNone(PyObject **p) {
  81. if (*p == NULL) {
  82. Py_INCREF(Py_None);
  83. *p = Py_None;
  84. }
  85. }
  86. void _CPy_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) {
  87. PyErr_GetExcInfo(p_type, p_value, p_traceback);
  88. _CPy_ToNone(p_type);
  89. _CPy_ToNone(p_value);
  90. _CPy_ToNone(p_traceback);
  91. }
  92. tuple_T3OOO CPy_GetExcInfo(void) {
  93. tuple_T3OOO ret;
  94. _CPy_GetExcInfo(&ret.f0, &ret.f1, &ret.f2);
  95. return ret;
  96. }
  97. void CPyError_OutOfMemory(void) {
  98. fprintf(stderr, "fatal: out of memory\n");
  99. fflush(stderr);
  100. abort();
  101. }
  102. // Construct a nicely formatted type name based on __module__ and __name__.
  103. static PyObject *CPy_GetTypeName(PyObject *type) {
  104. PyObject *module = NULL, *name = NULL;
  105. PyObject *full = NULL;
  106. module = PyObject_GetAttrString(type, "__module__");
  107. if (!module || !PyUnicode_Check(module)) {
  108. goto out;
  109. }
  110. name = PyObject_GetAttrString(type, "__qualname__");
  111. if (!name || !PyUnicode_Check(name)) {
  112. goto out;
  113. }
  114. if (PyUnicode_CompareWithASCIIString(module, "builtins") == 0) {
  115. Py_INCREF(name);
  116. full = name;
  117. } else {
  118. full = PyUnicode_FromFormat("%U.%U", module, name);
  119. }
  120. out:
  121. Py_XDECREF(module);
  122. Py_XDECREF(name);
  123. return full;
  124. }
  125. // Get the type of a value as a string, expanding tuples to include
  126. // all the element types.
  127. static PyObject *CPy_FormatTypeName(PyObject *value) {
  128. if (Py_IsNone(value)) {
  129. return PyUnicode_FromString("None");
  130. }
  131. if (!PyTuple_CheckExact(value)) {
  132. return CPy_GetTypeName((PyObject *)Py_TYPE(value));
  133. }
  134. if (PyTuple_GET_SIZE(value) > 10) {
  135. return PyUnicode_FromFormat("tuple[<%d items>]", PyTuple_GET_SIZE(value));
  136. }
  137. // Most of the logic is all for tuples, which is the only interesting case
  138. PyObject *output = PyUnicode_FromString("tuple[");
  139. if (!output) {
  140. return NULL;
  141. }
  142. /* This is quadratic but if that ever matters something is really weird. */
  143. int i;
  144. for (i = 0; i < PyTuple_GET_SIZE(value); i++) {
  145. PyObject *s = CPy_FormatTypeName(PyTuple_GET_ITEM(value, i));
  146. if (!s) {
  147. Py_DECREF(output);
  148. return NULL;
  149. }
  150. PyObject *next = PyUnicode_FromFormat("%U%U%s", output, s,
  151. i + 1 == PyTuple_GET_SIZE(value) ? "]" : ", ");
  152. Py_DECREF(output);
  153. Py_DECREF(s);
  154. if (!next) {
  155. return NULL;
  156. }
  157. output = next;
  158. }
  159. return output;
  160. }
  161. CPy_NOINLINE
  162. void CPy_TypeError(const char *expected, PyObject *value) {
  163. PyObject *out = CPy_FormatTypeName(value);
  164. if (out) {
  165. PyErr_Format(PyExc_TypeError, "%s object expected; got %U", expected, out);
  166. Py_DECREF(out);
  167. } else {
  168. PyErr_Format(PyExc_TypeError, "%s object expected; and errored formatting real type!",
  169. expected);
  170. }
  171. }
  172. // The PyFrameObject type definition (struct _frame) has been moved
  173. // to the internal C API: to the pycore_frame.h header file.
  174. // https://github.com/python/cpython/pull/31530
  175. #if PY_VERSION_HEX >= 0x030b00a6
  176. #include "internal/pycore_frame.h"
  177. #endif
  178. // This function is basically exactly the same with _PyTraceback_Add
  179. // which is available in all the versions we support.
  180. // We're continuing to use this because we'll probably optimize this later.
  181. void CPy_AddTraceback(const char *filename, const char *funcname, int line, PyObject *globals) {
  182. PyObject *exc, *val, *tb;
  183. PyThreadState *thread_state = PyThreadState_GET();
  184. PyFrameObject *frame_obj;
  185. // We need to save off the exception state because in 3.8,
  186. // PyFrame_New fails if there is an error set and it fails to look
  187. // up builtins in the globals. (_PyTraceback_Add documents that it
  188. // needs to do it because it decodes the filename according to the
  189. // FS encoding, which could have a decoder in Python. We don't do
  190. // that so *that* doesn't apply to us.)
  191. PyErr_Fetch(&exc, &val, &tb);
  192. PyCodeObject *code_obj = PyCode_NewEmpty(filename, funcname, line);
  193. if (code_obj == NULL) {
  194. goto error;
  195. }
  196. frame_obj = PyFrame_New(thread_state, code_obj, globals, 0);
  197. if (frame_obj == NULL) {
  198. Py_DECREF(code_obj);
  199. goto error;
  200. }
  201. frame_obj->f_lineno = line;
  202. PyErr_Restore(exc, val, tb);
  203. PyTraceBack_Here(frame_obj);
  204. Py_DECREF(code_obj);
  205. Py_DECREF(frame_obj);
  206. return;
  207. error:
  208. #if CPY_3_12_FEATURES
  209. _PyErr_ChainExceptions1(exc);
  210. #else
  211. _PyErr_ChainExceptions(exc, val, tb);
  212. #endif
  213. }
  214. CPy_NOINLINE
  215. void CPy_TypeErrorTraceback(const char *filename, const char *funcname, int line,
  216. PyObject *globals, const char *expected, PyObject *value) {
  217. CPy_TypeError(expected, value);
  218. CPy_AddTraceback(filename, funcname, line, globals);
  219. }
  220. void CPy_AttributeError(const char *filename, const char *funcname, const char *classname,
  221. const char *attrname, int line, PyObject *globals) {
  222. char buf[500];
  223. snprintf(buf, sizeof(buf), "attribute '%.200s' of '%.200s' undefined", attrname, classname);
  224. PyErr_SetString(PyExc_AttributeError, buf);
  225. CPy_AddTraceback(filename, funcname, line, globals);
  226. }