pycppwrapper_util.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef __PYCPPWRAPPER_UTIL_H
  15. #define __PYCPPWRAPPER_UTIL_H 1
  16. #include <Python.h>
  17. #include <exceptions/exceptions.h>
  18. /**
  19. * @file pycppwrapper_util.h
  20. * @short Shared definitions for python/C(++) API
  21. *
  22. * This utility defines a set of convenient wrappers for the python C API
  23. * to use it safely from our C++ bindings. The python C API has many pitfalls
  24. * such as not-so-consistent reference count policies. Also, many existing
  25. * examples are careless about error handling. It's easy to find on the net
  26. * example (even of "production use") python extensions like this:
  27. *
  28. * \code
  29. * new_exception = PyErr_NewException("mymodule.Exception", NULL, NULL);
  30. * // new_exception can be NULL, in which case the call to
  31. * // PyModule_AddObject will cause a surprising disruption.
  32. * PyModule_AddObject(mymodule, "Exception", new_exception); \endcode
  33. *
  34. * When using the python C API with C++, we should also be careful about
  35. * exception safety. The underlying C++ code (including standard C++ libraries
  36. * and memory allocation) can throw exceptions, in which case we need to
  37. * make sure any intermediate python objects are cleaned up (we also need to
  38. * catch the C++ exceptions inside the binding and convert them to python
  39. * errors, but that's a different subject). This is not a trivial task
  40. * because the python objects are represented as bare C pointers (so there's
  41. * no destructor) and we need to address the exception safety along with python
  42. * reference counters (so we cannot naively apply standard smart pointers).
  43. *
  44. * This utility tries to help address these issues.
  45. *
  46. * Also, it's intentional that this is a header-only utility. This way the
  47. * C++ loadable module won't depend on another C++ library (which is not
  48. * necessarily wrong, but would increase management cost such as link-time
  49. * troubles only for a small utility feature).
  50. */
  51. namespace isc {
  52. namespace util {
  53. namespace python {
  54. /// This is thrown inside this utility when it finds a NULL pointer is passed
  55. /// when it should not be NULL.
  56. class PyCPPWrapperException : public isc::Exception {
  57. public:
  58. PyCPPWrapperException(const char* file, size_t line, const char* what) :
  59. isc::Exception(file, line, what) {}
  60. };
  61. /// This helper class is similar to the standard autoptr and manages PyObject
  62. /// using some kind of RAII techniques. It is, however, customized for the
  63. /// python C API.
  64. ///
  65. /// A PyObjectContainer object is constructed with a pointer to PyObject,
  66. /// which is often just created dynamically. The caller will eventually
  67. /// attach the object to a different python object (often a module or class)
  68. /// via specific methods or directly return it to the python interpreter.
  69. ///
  70. /// There are two cases in destructing the object: with or without decreasing
  71. /// a reference to the PyObject. If the object is intended to be an argument
  72. /// to another python C library that increases the reference to the object for
  73. /// itself, we should normally release our own reference; otherwise the
  74. /// reference will leak and the object won't be garbage collected. Also, when
  75. /// an unexpected error happens in the form of C++ exception, we should
  76. /// release the reference to prevent resource leak.
  77. ///
  78. /// In some other cases, we should simply give our reference to the caller.
  79. /// That is the case when the created object itself is a return value of
  80. /// an extended python method written in the C++ binding. Likewise, some
  81. /// python C library functions "steal" the reference. In these cases we
  82. /// should not decrease the reference; otherwise it would cause duplicate free.
  83. ///
  84. /// By default, the destructor of this class releases the reference to the
  85. /// PyObject. If this behavior is desirable, you can extract the original
  86. /// bare pointer to the PyObject by the \c get() method. If you don't want
  87. /// the reference to be decreased, the original bare pointer should be
  88. /// extracted using the \c release() method.
  89. ///
  90. /// In some other cases, it would be convenient if it's possible to create
  91. /// an "empty" container and reset it with a Python object later.
  92. /// For example, we may want to create a temporary Python object in the
  93. /// middle of a function and make sure that it's valid within the rest of
  94. /// the function scope, while we want to make sure its reference is released
  95. /// when the function returns (either normally or as a result of exception).
  96. /// To allow this scenario, this class defines the default constructor
  97. /// and the \c reset() method. The default constructor allows the class
  98. /// object with an "empty" (NULL) Python object, while \c reset() allows
  99. /// the stored object to be replaced with a new one. If there's a valid
  100. /// object was already set, \c reset() releases its reference.
  101. /// In general, it's safer to construct the container object with a valid
  102. /// Python object pointer. The use of the default constructor and
  103. /// \c reset() should therefore be restricted to cases where it's
  104. /// absolutely necessary.
  105. ///
  106. /// There are two convenience methods for commonly used operations:
  107. /// \c installAsClassVariable() to add the PyObject as a class variable
  108. /// and \c installToModule to add the PyObject to a specified python module.
  109. /// These methods (at least to some extent) take care of the reference to
  110. /// the object (either release or keep) depending on the usage context so
  111. /// that the user don't have to worry about it.
  112. ///
  113. /// On construction, this class expects the pointer can be NULL.
  114. /// If it happens it immediately throws a \c PyCPPWrapperException exception.
  115. /// This behavior is to convert failures in the python C API (such as
  116. /// PyObject_New() returning NULL) to C++ exception so that we can unify
  117. /// error handling in the style of C++ exceptions.
  118. ///
  119. /// Examples 1: To create a tuple of two python objects, do this:
  120. ///
  121. /// \code
  122. /// try {
  123. /// PyObjectContainer container0(Py_BuildValue("I", 0));
  124. /// PyObjectContainer container1(Py_BuildValue("s", cppobj.toText().c_str()));
  125. /// return (Py_BuildValue("OO", container0.get(), container1.get()));
  126. /// } catch { ... set python exception, etc ... } \endcode
  127. ///
  128. /// Commonly deployed buggy implementation to achieve this would be like this:
  129. /// \code
  130. /// return (Py_BuildValue("OO", Py_BuildValue("I", 0),
  131. /// Py_BuildValue("s", cppobj.toText().c_str())));
  132. /// \endcode
  133. /// One clear bug of this code is that references to the element objects of
  134. /// the tuple will leak.
  135. /// (Assuming \c cppobj.toText() can throw) this code is also not exception
  136. /// safe; if \c cppobj.toText() throws the reference to the first object
  137. /// will leak, even if the code tried to do the necessary cleanup in the
  138. /// successful case.
  139. /// Further, this code naively passes the result of the first two calls to
  140. /// \c Py_BuildValue() to the third one even if they can be NULL.
  141. /// In this specific case, it happens to be okay because \c Py_BuildValue()
  142. /// accepts NULL and treats it as an indication of error. But not all
  143. /// python C library works that way (remember, the API is so inconsistent)
  144. /// and we need to refer to the API manual every time we have to worry about
  145. /// passing a NULL object to a library function. We'd certainly like to
  146. /// avoid such development overhead. The code using \c PyObjectContainer
  147. /// addresses all these problems.
  148. ///
  149. /// Examples 2: Install a (constant) variable to a class.
  150. ///
  151. /// \code
  152. /// try {
  153. /// // installClassVariable is a wrapper of
  154. /// // PyObjectContainer::installAsClassVariable. See below.
  155. /// installClassVariable(myclass_type, "SOME_CONSTANT",
  156. /// Py_BuildValue("I", 0));
  157. /// } catch { ... }
  158. /// \endcode
  159. ///
  160. /// Examples 3: Install a custom exception to a module.
  161. ///
  162. /// \code
  163. /// PyObject* new_exception; // publicly visible
  164. /// ...
  165. /// try {
  166. /// new_exception = PyErr_NewException("mymodule.NewException",
  167. /// NULL, NULL);
  168. /// PyObjectContainer(new_exception).installToModule(mymodule,
  169. /// "NewException");
  170. /// } catch { ... }
  171. /// \endcode
  172. ///
  173. /// Note that \c installToModule() keeps the reference to \c new_exception
  174. /// by default. This is a common practice when we introduce a custom
  175. /// exception in a python biding written in C/C++. See the code comment
  176. /// of the method for more details.
  177. struct PyObjectContainer {
  178. PyObjectContainer() : obj_(NULL) {}
  179. PyObjectContainer(PyObject* obj) : obj_(obj) {
  180. if (obj_ == NULL) {
  181. isc_throw(PyCPPWrapperException, "Unexpected NULL PyObject, "
  182. "probably due to short memory");
  183. }
  184. }
  185. ~PyObjectContainer() {
  186. if (obj_ != NULL) {
  187. Py_DECREF(obj_);
  188. }
  189. }
  190. void reset(PyObject* obj) {
  191. if (obj == NULL) {
  192. isc_throw(PyCPPWrapperException, "Unexpected NULL PyObject, "
  193. "probably due to short memory");
  194. }
  195. if (obj_ != NULL) {
  196. Py_DECREF(obj_);
  197. }
  198. obj_ = obj;
  199. }
  200. PyObject* get() {
  201. return (obj_);
  202. }
  203. PyObject* release() {
  204. PyObject* ret = obj_;
  205. obj_ = NULL;
  206. return (ret);
  207. }
  208. // Install the enclosed PyObject to the specified python class 'pyclass'
  209. // as a variable named 'name'.
  210. void installAsClassVariable(PyTypeObject& pyclass, const char* name) {
  211. if (PyDict_SetItemString(pyclass.tp_dict, name, obj_) < 0) {
  212. isc_throw(PyCPPWrapperException, "Failed to set a class variable, "
  213. "probably due to short memory");
  214. }
  215. // Ownership successfully transferred to the class object. We'll let
  216. // it be released in the destructor.
  217. }
  218. // Install the enclosed PyObject to the specified module 'mod' as an
  219. // object named 'name'.
  220. // By default, this method explicitly keeps the reference to the object
  221. // even after the module "steals" it. To cancel this behavior and give
  222. // the reference to the module completely, the third parameter 'keep_ref'
  223. // should be set to false.
  224. void installToModule(PyObject* mod, const char* name,
  225. bool keep_ref = true)
  226. {
  227. if (PyModule_AddObject(mod, name, obj_) < 0) {
  228. isc_throw(PyCPPWrapperException, "Failed to add an object to "
  229. "module, probably due to short memory");
  230. }
  231. // PyModule_AddObject has "stolen" the reference, so unless we
  232. // have to retain it ourselves we don't (shouldn't) decrease it.
  233. // However, we actually often need to keep our own reference because
  234. // objects added to a module are often referenced via non local
  235. // C/C++ variables in various places of the C/C++ code. In order
  236. // for the code to run safely even if some buggy/evil python program
  237. // performs 'del mod.obj', we need the extra reference. See, e.g.:
  238. // http://docs.python.org/py3k/c-api/init.html#Py_Initialize
  239. // http://mail.python.org/pipermail/python-dev/2005-June/054238.html
  240. if (keep_ref) {
  241. Py_INCREF(obj_);
  242. }
  243. obj_ = NULL;
  244. }
  245. protected:
  246. PyObject* obj_;
  247. };
  248. /// This templated class is a derived class of \c PyObjectContainer and
  249. /// manages C++-class based python objects.
  250. ///
  251. /// The template parameter \c PYSTRUCT must be a derived class (structure) of
  252. /// \c PyObject that has a member variable named \c cppobj, which must be a
  253. /// a pointer to \c CPPCLASS (the second template parameter).
  254. ///
  255. /// For example, to define a custom python class based on a C++ class, MyClass,
  256. /// we'd define a class (struct) named \c s_MyClass like this:
  257. /// \code
  258. /// class s_MyClass : public PyObject {
  259. /// public:
  260. /// s_MyClass() : cppobj(NULL) {}
  261. /// MyClass* cppobj;
  262. /// };
  263. /// \endcode
  264. ///
  265. /// And, to build and return a python version of MyClass object, write the
  266. /// following C++ code:
  267. /// \code
  268. /// typedef CPPPyObjectContainer<s_MyClass, MyClass> MyContainer;
  269. /// try {
  270. /// // below, myclass_type is of \c PyTypeObject that defines
  271. /// // a python class (type) for MyClass
  272. /// MyContainer container(PyObject_New(s_MyClass, myclass_type));
  273. /// container.set(new MyClass());
  274. /// return (container.release()); // give the reference to the caller
  275. /// } catch { ... }
  276. /// \endcode
  277. ///
  278. /// This code prevents bugs like NULL pointer dereference when \c PyObject_New
  279. /// fails or resource leaks when new'ing \c MyClass results in an exception.
  280. /// Note that we use \c release() (derived from the base class) instead of
  281. /// \c get(); in this case we should simply pass the reference generated in
  282. /// \c PyObject_New() to the caller.
  283. template <typename PYSTRUCT, typename CPPCLASS>
  284. struct CPPPyObjectContainer : public PyObjectContainer {
  285. explicit CPPPyObjectContainer(PYSTRUCT* obj) : PyObjectContainer(obj) {}
  286. // This method associates a C++ object with the corresponding python
  287. // object enclosed in this class.
  288. void set(CPPCLASS* value) {
  289. if (value == NULL) {
  290. isc_throw(PyCPPWrapperException, "Unexpected NULL C++ object, "
  291. "probably due to short memory");
  292. }
  293. static_cast<PYSTRUCT*>(obj_)->cppobj = value;
  294. }
  295. // This is a convenience short cut to associate a C++ object with the
  296. // python object and install it to the specified python class \c pyclass
  297. // as a variable named \c name.
  298. void installAsClassVariable(PyTypeObject& pyclass, const char* name,
  299. CPPCLASS* value)
  300. {
  301. set(value);
  302. PyObjectContainer::installAsClassVariable(pyclass, name);
  303. }
  304. };
  305. /// A shortcut function to install a python class variable.
  306. ///
  307. /// It installs a python object \c obj to a specified class \c pyclass
  308. /// as a variable named \c name.
  309. inline void
  310. installClassVariable(PyTypeObject& pyclass, const char* name, PyObject* obj) {
  311. PyObjectContainer(obj).installAsClassVariable(pyclass, name);
  312. }
  313. } // namespace python
  314. } // namespace util
  315. } // namespace isc
  316. #endif // __PYCPPWRAPPER_UTIL_H
  317. // Local Variables:
  318. // mode: c++
  319. // End: