protobuf.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * Copyright (c) 2009-2021, Google LLC
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of Google LLC nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
  20. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include "python/protobuf.h"
  28. #include "python/descriptor.h"
  29. #include "python/descriptor_containers.h"
  30. #include "python/descriptor_pool.h"
  31. #include "python/extension_dict.h"
  32. #include "python/map.h"
  33. #include "python/message.h"
  34. #include "python/repeated.h"
  35. static void PyUpb_ModuleDealloc(void* module) {
  36. PyUpb_ModuleState* s = PyModule_GetState(module);
  37. PyUpb_WeakMap_Free(s->obj_cache);
  38. if (s->c_descriptor_symtab) {
  39. upb_DefPool_Free(s->c_descriptor_symtab);
  40. }
  41. }
  42. PyObject* PyUpb_SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
  43. if (!arg || !PyBool_Check(arg)) {
  44. PyErr_SetString(PyExc_TypeError,
  45. "Argument to SetAllowOversizeProtos must be boolean");
  46. return NULL;
  47. }
  48. PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
  49. state->allow_oversize_protos = PyObject_IsTrue(arg);
  50. Py_INCREF(arg);
  51. return arg;
  52. }
  53. static PyMethodDef PyUpb_ModuleMethods[] = {
  54. {"SetAllowOversizeProtos", PyUpb_SetAllowOversizeProtos, METH_O,
  55. "Enable/disable oversize proto parsing."},
  56. {NULL, NULL}};
  57. static struct PyModuleDef module_def = {PyModuleDef_HEAD_INIT,
  58. PYUPB_MODULE_NAME,
  59. "Protobuf Module",
  60. sizeof(PyUpb_ModuleState),
  61. PyUpb_ModuleMethods, // m_methods
  62. NULL, // m_slots
  63. NULL, // m_traverse
  64. NULL, // m_clear
  65. PyUpb_ModuleDealloc};
  66. // -----------------------------------------------------------------------------
  67. // ModuleState
  68. // -----------------------------------------------------------------------------
  69. PyUpb_ModuleState* PyUpb_ModuleState_MaybeGet(void) {
  70. PyObject* module = PyState_FindModule(&module_def);
  71. return module ? PyModule_GetState(module) : NULL;
  72. }
  73. PyUpb_ModuleState* PyUpb_ModuleState_GetFromModule(PyObject* module) {
  74. PyUpb_ModuleState* state = PyModule_GetState(module);
  75. assert(state);
  76. assert(PyModule_GetDef(module) == &module_def);
  77. return state;
  78. }
  79. PyUpb_ModuleState* PyUpb_ModuleState_Get(void) {
  80. PyObject* module = PyState_FindModule(&module_def);
  81. assert(module);
  82. return PyUpb_ModuleState_GetFromModule(module);
  83. }
  84. PyObject* PyUpb_GetWktBases(PyUpb_ModuleState* state) {
  85. if (!state->wkt_bases) {
  86. PyObject* wkt_module =
  87. PyImport_ImportModule("google.protobuf.internal.well_known_types");
  88. if (wkt_module == NULL) {
  89. return false;
  90. }
  91. state->wkt_bases = PyObject_GetAttrString(wkt_module, "WKTBASES");
  92. PyObject* m = PyState_FindModule(&module_def);
  93. // Reparent ownership to m.
  94. PyModule_AddObject(m, "__internal_wktbases", state->wkt_bases);
  95. Py_DECREF(wkt_module);
  96. }
  97. return state->wkt_bases;
  98. }
  99. // -----------------------------------------------------------------------------
  100. // WeakMap
  101. // -----------------------------------------------------------------------------
  102. struct PyUpb_WeakMap {
  103. upb_inttable table;
  104. upb_Arena* arena;
  105. };
  106. PyUpb_WeakMap* PyUpb_WeakMap_New(void) {
  107. upb_Arena* arena = upb_Arena_New();
  108. PyUpb_WeakMap* map = upb_Arena_Malloc(arena, sizeof(*map));
  109. map->arena = arena;
  110. upb_inttable_init(&map->table, map->arena);
  111. return map;
  112. }
  113. void PyUpb_WeakMap_Free(PyUpb_WeakMap* map) { upb_Arena_Free(map->arena); }
  114. uintptr_t PyUpb_WeakMap_GetKey(const void* key) {
  115. uintptr_t n = (uintptr_t)key;
  116. assert((n & 7) == 0);
  117. return n >> 3;
  118. }
  119. void PyUpb_WeakMap_Add(PyUpb_WeakMap* map, const void* key, PyObject* py_obj) {
  120. upb_inttable_insert(&map->table, PyUpb_WeakMap_GetKey(key),
  121. upb_value_ptr(py_obj), map->arena);
  122. }
  123. void PyUpb_WeakMap_Delete(PyUpb_WeakMap* map, const void* key) {
  124. upb_value val;
  125. bool removed =
  126. upb_inttable_remove(&map->table, PyUpb_WeakMap_GetKey(key), &val);
  127. (void)removed;
  128. assert(removed);
  129. }
  130. void PyUpb_WeakMap_TryDelete(PyUpb_WeakMap* map, const void* key) {
  131. upb_inttable_remove(&map->table, PyUpb_WeakMap_GetKey(key), NULL);
  132. }
  133. PyObject* PyUpb_WeakMap_Get(PyUpb_WeakMap* map, const void* key) {
  134. upb_value val;
  135. if (upb_inttable_lookup(&map->table, PyUpb_WeakMap_GetKey(key), &val)) {
  136. PyObject* ret = upb_value_getptr(val);
  137. Py_INCREF(ret);
  138. return ret;
  139. } else {
  140. return NULL;
  141. }
  142. }
  143. bool PyUpb_WeakMap_Next(PyUpb_WeakMap* map, const void** key, PyObject** obj,
  144. intptr_t* iter) {
  145. uintptr_t u_key;
  146. upb_value val;
  147. if (!upb_inttable_next2(&map->table, &u_key, &val, iter)) return false;
  148. *key = (void*)(u_key << 3);
  149. *obj = upb_value_getptr(val);
  150. return true;
  151. }
  152. void PyUpb_WeakMap_DeleteIter(PyUpb_WeakMap* map, intptr_t* iter) {
  153. upb_inttable_removeiter(&map->table, iter);
  154. }
  155. // -----------------------------------------------------------------------------
  156. // ObjCache
  157. // -----------------------------------------------------------------------------
  158. PyUpb_WeakMap* PyUpb_ObjCache_Instance(void) {
  159. PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
  160. return state->obj_cache;
  161. }
  162. void PyUpb_ObjCache_Add(const void* key, PyObject* py_obj) {
  163. PyUpb_WeakMap_Add(PyUpb_ObjCache_Instance(), key, py_obj);
  164. }
  165. void PyUpb_ObjCache_Delete(const void* key) {
  166. PyUpb_ModuleState* state = PyUpb_ModuleState_MaybeGet();
  167. if (!state) {
  168. // During the shutdown sequence, our object's Dealloc() methods can be
  169. // called *after* our module Dealloc() method has been called. At that
  170. // point our state will be NULL and there is nothing to delete out of the
  171. // map.
  172. return;
  173. }
  174. PyUpb_WeakMap_Delete(state->obj_cache, key);
  175. }
  176. PyObject* PyUpb_ObjCache_Get(const void* key) {
  177. return PyUpb_WeakMap_Get(PyUpb_ObjCache_Instance(), key);
  178. }
  179. // -----------------------------------------------------------------------------
  180. // Arena
  181. // -----------------------------------------------------------------------------
  182. typedef struct {
  183. PyObject_HEAD;
  184. upb_Arena* arena;
  185. } PyUpb_Arena;
  186. PyObject* PyUpb_Arena_New(void) {
  187. PyUpb_ModuleState* state = PyUpb_ModuleState_Get();
  188. PyUpb_Arena* arena = (void*)PyType_GenericAlloc(state->arena_type, 0);
  189. arena->arena = upb_Arena_New();
  190. return &arena->ob_base;
  191. }
  192. static void PyUpb_Arena_Dealloc(PyObject* self) {
  193. upb_Arena_Free(PyUpb_Arena_Get(self));
  194. PyUpb_Dealloc(self);
  195. }
  196. upb_Arena* PyUpb_Arena_Get(PyObject* arena) {
  197. return ((PyUpb_Arena*)arena)->arena;
  198. }
  199. static PyType_Slot PyUpb_Arena_Slots[] = {
  200. {Py_tp_dealloc, PyUpb_Arena_Dealloc},
  201. {0, NULL},
  202. };
  203. static PyType_Spec PyUpb_Arena_Spec = {
  204. PYUPB_MODULE_NAME ".Arena",
  205. sizeof(PyUpb_Arena),
  206. 0, // itemsize
  207. Py_TPFLAGS_DEFAULT,
  208. PyUpb_Arena_Slots,
  209. };
  210. static bool PyUpb_InitArena(PyObject* m) {
  211. PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
  212. state->arena_type = PyUpb_AddClass(m, &PyUpb_Arena_Spec);
  213. return state->arena_type;
  214. }
  215. // -----------------------------------------------------------------------------
  216. // Utilities
  217. // -----------------------------------------------------------------------------
  218. PyTypeObject* AddObject(PyObject* m, const char* name, PyType_Spec* spec) {
  219. PyObject* type = PyType_FromSpec(spec);
  220. return type && PyModule_AddObject(m, name, type) == 0 ? (PyTypeObject*)type
  221. : NULL;
  222. }
  223. static const char* PyUpb_GetClassName(PyType_Spec* spec) {
  224. // spec->name contains a fully-qualified name, like:
  225. // google.protobuf.pyext._message.FooBar
  226. //
  227. // Find the rightmost '.' to get "FooBar".
  228. const char* name = strrchr(spec->name, '.');
  229. assert(name);
  230. return name + 1;
  231. }
  232. PyTypeObject* PyUpb_AddClass(PyObject* m, PyType_Spec* spec) {
  233. PyObject* type = PyType_FromSpec(spec);
  234. const char* name = PyUpb_GetClassName(spec);
  235. if (PyModule_AddObject(m, name, type) < 0) {
  236. Py_XDECREF(type);
  237. return NULL;
  238. }
  239. return (PyTypeObject*)type;
  240. }
  241. PyTypeObject* PyUpb_AddClassWithBases(PyObject* m, PyType_Spec* spec,
  242. PyObject* bases) {
  243. PyObject* type = PyType_FromSpecWithBases(spec, bases);
  244. const char* name = PyUpb_GetClassName(spec);
  245. if (PyModule_AddObject(m, name, type) < 0) {
  246. Py_XDECREF(type);
  247. return NULL;
  248. }
  249. return (PyTypeObject*)type;
  250. }
  251. const char* PyUpb_GetStrData(PyObject* obj) {
  252. if (PyUnicode_Check(obj)) {
  253. return PyUnicode_AsUTF8AndSize(obj, NULL);
  254. } else if (PyBytes_Check(obj)) {
  255. return PyBytes_AsString(obj);
  256. } else {
  257. return NULL;
  258. }
  259. }
  260. const char* PyUpb_VerifyStrData(PyObject* obj) {
  261. const char* ret = PyUpb_GetStrData(obj);
  262. if (ret) return ret;
  263. PyErr_Format(PyExc_TypeError, "Expected string: %S", obj);
  264. return NULL;
  265. }
  266. PyObject* PyUpb_Forbidden_New(PyObject* cls, PyObject* args, PyObject* kwds) {
  267. PyObject* name = PyObject_GetAttrString(cls, "__name__");
  268. PyErr_Format(PyExc_RuntimeError,
  269. "Objects of type %U may not be created directly.", name);
  270. Py_XDECREF(name);
  271. return NULL;
  272. }
  273. // -----------------------------------------------------------------------------
  274. // Module Entry Point
  275. // -----------------------------------------------------------------------------
  276. PyMODINIT_FUNC PyInit__message(void) {
  277. PyObject* m = PyModule_Create(&module_def);
  278. if (!m) return NULL;
  279. PyUpb_ModuleState* state = PyUpb_ModuleState_GetFromModule(m);
  280. state->allow_oversize_protos = false;
  281. state->wkt_bases = NULL;
  282. state->obj_cache = PyUpb_WeakMap_New();
  283. state->c_descriptor_symtab = NULL;
  284. if (!PyUpb_InitDescriptorContainers(m) || !PyUpb_InitDescriptorPool(m) ||
  285. !PyUpb_InitDescriptor(m) || !PyUpb_InitArena(m) ||
  286. !PyUpb_InitExtensionDict(m) || !PyUpb_Map_Init(m) ||
  287. !PyUpb_InitMessage(m) || !PyUpb_Repeated_Init(m)) {
  288. Py_DECREF(m);
  289. return NULL;
  290. }
  291. // Temporary: an cookie we can use in the tests to ensure we are testing upb
  292. // and not another protobuf library on the system.
  293. PyModule_AddIntConstant(m, "_IS_UPB", 1);
  294. return m;
  295. }