greenlet_exceptions.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #ifndef GREENLET_EXCEPTIONS_HPP
  2. #define GREENLET_EXCEPTIONS_HPP
  3. #define PY_SSIZE_T_CLEAN
  4. #include <Python.h>
  5. #include <stdexcept>
  6. #include <string>
  7. #ifdef __clang__
  8. # pragma clang diagnostic push
  9. # pragma clang diagnostic ignored "-Wunused-function"
  10. #endif
  11. namespace greenlet {
  12. class PyErrOccurred : public std::runtime_error
  13. {
  14. public:
  15. // CAUTION: In debug builds, may run arbitrary Python code.
  16. static const PyErrOccurred
  17. from_current()
  18. {
  19. assert(PyErr_Occurred());
  20. #ifndef NDEBUG
  21. // This is not exception safe, and
  22. // not necessarily safe in general (what if it switches?)
  23. // But we only do this in debug mode, where we are in
  24. // tight control of what exceptions are getting raised and
  25. // can prevent those issues.
  26. // You can't call PyObject_Str with a pending exception.
  27. PyObject* typ;
  28. PyObject* val;
  29. PyObject* tb;
  30. PyErr_Fetch(&typ, &val, &tb);
  31. PyObject* typs = PyObject_Str(typ);
  32. PyObject* vals = PyObject_Str(val ? val : typ);
  33. const char* typ_msg = PyUnicode_AsUTF8(typs);
  34. const char* val_msg = PyUnicode_AsUTF8(vals);
  35. PyErr_Restore(typ, val, tb);
  36. std::string msg(typ_msg);
  37. msg += ": ";
  38. msg += val_msg;
  39. PyErrOccurred ex(msg);
  40. Py_XDECREF(typs);
  41. Py_XDECREF(vals);
  42. return ex;
  43. #else
  44. return PyErrOccurred();
  45. #endif
  46. }
  47. PyErrOccurred() : std::runtime_error("")
  48. {
  49. assert(PyErr_Occurred());
  50. }
  51. PyErrOccurred(const std::string& msg) : std::runtime_error(msg)
  52. {
  53. assert(PyErr_Occurred());
  54. }
  55. PyErrOccurred(PyObject* exc_kind, const char* const msg)
  56. : std::runtime_error(msg)
  57. {
  58. PyErr_SetString(exc_kind, msg);
  59. }
  60. PyErrOccurred(PyObject* exc_kind, const std::string msg)
  61. : std::runtime_error(msg)
  62. {
  63. // This copies the c_str, so we don't have any lifetime
  64. // issues to worry about.
  65. PyErr_SetString(exc_kind, msg.c_str());
  66. }
  67. PyErrOccurred(PyObject* exc_kind,
  68. const std::string msg, //This is the format
  69. //string; that's not
  70. //usually safe!
  71. PyObject* borrowed_obj_one, PyObject* borrowed_obj_two)
  72. : std::runtime_error(msg)
  73. {
  74. //This is designed specifically for the
  75. //``check_switch_allowed`` function.
  76. // PyObject_Str and PyObject_Repr are safe to call with
  77. // NULL pointers; they return the string "<NULL>" in that
  78. // case.
  79. // This function always returns null.
  80. PyErr_Format(exc_kind,
  81. msg.c_str(),
  82. borrowed_obj_one, borrowed_obj_two);
  83. }
  84. };
  85. class TypeError : public PyErrOccurred
  86. {
  87. public:
  88. TypeError(const char* const what)
  89. : PyErrOccurred(PyExc_TypeError, what)
  90. {
  91. }
  92. TypeError(const std::string what)
  93. : PyErrOccurred(PyExc_TypeError, what)
  94. {
  95. }
  96. };
  97. class ValueError : public PyErrOccurred
  98. {
  99. public:
  100. ValueError(const char* const what)
  101. : PyErrOccurred(PyExc_ValueError, what)
  102. {
  103. }
  104. };
  105. class AttributeError : public PyErrOccurred
  106. {
  107. public:
  108. AttributeError(const char* const what)
  109. : PyErrOccurred(PyExc_AttributeError, what)
  110. {
  111. }
  112. };
  113. /**
  114. * Calls `Py_FatalError` when constructed, so you can't actually
  115. * throw this. It just makes static analysis easier.
  116. */
  117. class PyFatalError : public std::runtime_error
  118. {
  119. public:
  120. PyFatalError(const char* const msg)
  121. : std::runtime_error(msg)
  122. {
  123. Py_FatalError(msg);
  124. }
  125. };
  126. static inline PyObject*
  127. Require(PyObject* p, const std::string& msg="")
  128. {
  129. if (!p) {
  130. throw PyErrOccurred(msg);
  131. }
  132. return p;
  133. };
  134. static inline void
  135. Require(const int retval)
  136. {
  137. if (retval < 0) {
  138. throw PyErrOccurred();
  139. }
  140. };
  141. };
  142. #ifdef __clang__
  143. # pragma clang diagnostic pop
  144. #endif
  145. #endif