bufferutil.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /**
  2. * Copyright (c) 2017-present, Gregory Szorc
  3. * All rights reserved.
  4. *
  5. * This software may be modified and distributed under the terms
  6. * of the BSD license. See the LICENSE file for details.
  7. */
  8. #include "python-zstandard.h"
  9. extern PyObject *ZstdError;
  10. static void BufferWithSegments_dealloc(ZstdBufferWithSegments *self) {
  11. /* Backing memory is either canonically owned by a Py_buffer or by us. */
  12. if (self->parent.buf) {
  13. PyBuffer_Release(&self->parent);
  14. }
  15. else if (self->useFree) {
  16. free(self->data);
  17. }
  18. else {
  19. PyMem_Free(self->data);
  20. }
  21. self->data = NULL;
  22. if (self->useFree) {
  23. free(self->segments);
  24. }
  25. else {
  26. PyMem_Free(self->segments);
  27. }
  28. self->segments = NULL;
  29. PyObject_Del(self);
  30. }
  31. static int BufferWithSegments_init(ZstdBufferWithSegments *self, PyObject *args,
  32. PyObject *kwargs) {
  33. static char *kwlist[] = {"data", "segments", NULL};
  34. Py_buffer segments;
  35. Py_ssize_t segmentCount;
  36. Py_ssize_t i;
  37. memset(&self->parent, 0, sizeof(self->parent));
  38. if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*y*:BufferWithSegments",
  39. kwlist, &self->parent, &segments)) {
  40. return -1;
  41. }
  42. if (segments.len % sizeof(BufferSegment)) {
  43. PyErr_Format(PyExc_ValueError,
  44. "segments array size is not a multiple of %zu",
  45. sizeof(BufferSegment));
  46. goto except;
  47. }
  48. segmentCount = segments.len / sizeof(BufferSegment);
  49. /* Validate segments data, as blindly trusting it could lead to arbitrary
  50. memory access. */
  51. for (i = 0; i < segmentCount; i++) {
  52. BufferSegment *segment = &((BufferSegment *)(segments.buf))[i];
  53. if (segment->offset + segment->length >
  54. (unsigned long long)self->parent.len) {
  55. PyErr_SetString(PyExc_ValueError,
  56. "offset within segments array references memory "
  57. "outside buffer");
  58. goto except;
  59. return -1;
  60. }
  61. }
  62. /* Make a copy of the segments data. It is cheap to do so and is a guard
  63. against caller changing offsets, which has security implications. */
  64. self->segments = PyMem_Malloc(segments.len);
  65. if (!self->segments) {
  66. PyErr_NoMemory();
  67. goto except;
  68. }
  69. memcpy(self->segments, segments.buf, segments.len);
  70. PyBuffer_Release(&segments);
  71. self->data = self->parent.buf;
  72. self->dataSize = self->parent.len;
  73. self->segmentCount = segmentCount;
  74. return 0;
  75. except:
  76. PyBuffer_Release(&self->parent);
  77. PyBuffer_Release(&segments);
  78. return -1;
  79. }
  80. /**
  81. * Construct a BufferWithSegments from existing memory and offsets.
  82. *
  83. * Ownership of the backing memory and BufferSegments will be transferred to
  84. * the created object and freed when the BufferWithSegments is destroyed.
  85. */
  86. ZstdBufferWithSegments *
  87. BufferWithSegments_FromMemory(void *data, unsigned long long dataSize,
  88. BufferSegment *segments,
  89. Py_ssize_t segmentsSize) {
  90. ZstdBufferWithSegments *result = NULL;
  91. Py_ssize_t i;
  92. if (NULL == data) {
  93. PyErr_SetString(PyExc_ValueError, "data is NULL");
  94. return NULL;
  95. }
  96. if (NULL == segments) {
  97. PyErr_SetString(PyExc_ValueError, "segments is NULL");
  98. return NULL;
  99. }
  100. for (i = 0; i < segmentsSize; i++) {
  101. BufferSegment *segment = &segments[i];
  102. if (segment->offset + segment->length > dataSize) {
  103. PyErr_SetString(PyExc_ValueError,
  104. "offset in segments overflows buffer size");
  105. return NULL;
  106. }
  107. }
  108. result = PyObject_New(ZstdBufferWithSegments, ZstdBufferWithSegmentsType);
  109. if (NULL == result) {
  110. return NULL;
  111. }
  112. result->useFree = 0;
  113. memset(&result->parent, 0, sizeof(result->parent));
  114. result->data = data;
  115. result->dataSize = dataSize;
  116. result->segments = segments;
  117. result->segmentCount = segmentsSize;
  118. return result;
  119. }
  120. static Py_ssize_t BufferWithSegments_length(ZstdBufferWithSegments *self) {
  121. return self->segmentCount;
  122. }
  123. static ZstdBufferSegment *BufferWithSegments_item(ZstdBufferWithSegments *self,
  124. Py_ssize_t i) {
  125. ZstdBufferSegment *result = NULL;
  126. if (i < 0) {
  127. PyErr_SetString(PyExc_IndexError, "offset must be non-negative");
  128. return NULL;
  129. }
  130. if (i >= self->segmentCount) {
  131. PyErr_Format(PyExc_IndexError, "offset must be less than %zd",
  132. self->segmentCount);
  133. return NULL;
  134. }
  135. if (self->segments[i].length > PY_SSIZE_T_MAX) {
  136. PyErr_Format(PyExc_ValueError,
  137. "item at offset %zd is too large for this platform", i);
  138. return NULL;
  139. }
  140. result = (ZstdBufferSegment *)PyObject_CallObject(
  141. (PyObject *)ZstdBufferSegmentType, NULL);
  142. if (NULL == result) {
  143. return NULL;
  144. }
  145. result->parent = (PyObject *)self;
  146. Py_INCREF(self);
  147. result->data = (char *)self->data + self->segments[i].offset;
  148. result->dataSize = (Py_ssize_t)self->segments[i].length;
  149. result->offset = self->segments[i].offset;
  150. return result;
  151. }
  152. static int BufferWithSegments_getbuffer(ZstdBufferWithSegments *self,
  153. Py_buffer *view, int flags) {
  154. if (self->dataSize > PY_SSIZE_T_MAX) {
  155. view->obj = NULL;
  156. PyErr_SetString(PyExc_BufferError,
  157. "buffer is too large for this platform");
  158. return -1;
  159. }
  160. return PyBuffer_FillInfo(view, (PyObject *)self, self->data,
  161. (Py_ssize_t)self->dataSize, 1, flags);
  162. }
  163. static PyObject *BufferWithSegments_tobytes(ZstdBufferWithSegments *self) {
  164. if (self->dataSize > PY_SSIZE_T_MAX) {
  165. PyErr_SetString(PyExc_ValueError,
  166. "buffer is too large for this platform");
  167. return NULL;
  168. }
  169. return PyBytes_FromStringAndSize(self->data, (Py_ssize_t)self->dataSize);
  170. }
  171. static ZstdBufferSegments *
  172. BufferWithSegments_segments(ZstdBufferWithSegments *self) {
  173. ZstdBufferSegments *result = (ZstdBufferSegments *)PyObject_CallObject(
  174. (PyObject *)ZstdBufferSegmentsType, NULL);
  175. if (NULL == result) {
  176. return NULL;
  177. }
  178. result->parent = (PyObject *)self;
  179. Py_INCREF(self);
  180. result->segments = self->segments;
  181. result->segmentCount = self->segmentCount;
  182. return result;
  183. }
  184. #if PY_VERSION_HEX < 0x03090000
  185. static PyBufferProcs BufferWithSegments_as_buffer = {
  186. (getbufferproc)BufferWithSegments_getbuffer, /* bf_getbuffer */
  187. 0 /* bf_releasebuffer */
  188. };
  189. #endif
  190. static PyMethodDef BufferWithSegments_methods[] = {
  191. {"segments", (PyCFunction)BufferWithSegments_segments, METH_NOARGS, NULL},
  192. {"tobytes", (PyCFunction)BufferWithSegments_tobytes, METH_NOARGS, NULL},
  193. {NULL, NULL}};
  194. static PyMemberDef BufferWithSegments_members[] = {
  195. {"size", T_ULONGLONG, offsetof(ZstdBufferWithSegments, dataSize), READONLY,
  196. "total size of the buffer in bytes"},
  197. {NULL}};
  198. PyType_Slot ZstdBufferWithSegmentsSlots[] = {
  199. {Py_tp_dealloc, BufferWithSegments_dealloc},
  200. {Py_sq_length, BufferWithSegments_length},
  201. {Py_sq_item, BufferWithSegments_item},
  202. #if PY_VERSION_HEX >= 0x03090000
  203. {Py_bf_getbuffer, BufferWithSegments_getbuffer},
  204. #endif
  205. {Py_tp_methods, BufferWithSegments_methods},
  206. {Py_tp_members, BufferWithSegments_members},
  207. {Py_tp_init, BufferWithSegments_init},
  208. {Py_tp_new, PyType_GenericNew},
  209. {0, NULL},
  210. };
  211. PyType_Spec ZstdBufferWithSegmentsSpec = {
  212. "zstd.BufferWithSegments",
  213. sizeof(ZstdBufferWithSegments),
  214. 0,
  215. Py_TPFLAGS_DEFAULT,
  216. ZstdBufferWithSegmentsSlots,
  217. };
  218. PyTypeObject *ZstdBufferWithSegmentsType;
  219. static void BufferSegments_dealloc(ZstdBufferSegments *self) {
  220. Py_CLEAR(self->parent);
  221. PyObject_Del(self);
  222. }
  223. static int BufferSegments_getbuffer(ZstdBufferSegments *self, Py_buffer *view,
  224. int flags) {
  225. return PyBuffer_FillInfo(view, (PyObject *)self, (void *)self->segments,
  226. self->segmentCount * sizeof(BufferSegment), 1,
  227. flags);
  228. }
  229. PyType_Slot ZstdBufferSegmentsSlots[] = {
  230. {Py_tp_dealloc, BufferSegments_dealloc},
  231. #if PY_VERSION_HEX >= 0x03090000
  232. {Py_bf_getbuffer, BufferSegments_getbuffer},
  233. #endif
  234. {Py_tp_new, PyType_GenericNew},
  235. {0, NULL},
  236. };
  237. PyType_Spec ZstdBufferSegmentsSpec = {
  238. "zstd.BufferSegments",
  239. sizeof(ZstdBufferSegments),
  240. 0,
  241. Py_TPFLAGS_DEFAULT,
  242. ZstdBufferSegmentsSlots,
  243. };
  244. #if PY_VERSION_HEX < 0x03090000
  245. static PyBufferProcs BufferSegments_as_buffer = {
  246. (getbufferproc)BufferSegments_getbuffer, 0};
  247. #endif
  248. PyTypeObject *ZstdBufferSegmentsType;
  249. static void BufferSegment_dealloc(ZstdBufferSegment *self) {
  250. Py_CLEAR(self->parent);
  251. PyObject_Del(self);
  252. }
  253. static Py_ssize_t BufferSegment_length(ZstdBufferSegment *self) {
  254. return self->dataSize;
  255. }
  256. static int BufferSegment_getbuffer(ZstdBufferSegment *self, Py_buffer *view,
  257. int flags) {
  258. return PyBuffer_FillInfo(view, (PyObject *)self, self->data, self->dataSize,
  259. 1, flags);
  260. }
  261. static PyObject *BufferSegment_tobytes(ZstdBufferSegment *self) {
  262. return PyBytes_FromStringAndSize(self->data, self->dataSize);
  263. }
  264. #if PY_VERSION_HEX < 0x03090000
  265. static PyBufferProcs BufferSegment_as_buffer = {
  266. (getbufferproc)BufferSegment_getbuffer, 0};
  267. #endif
  268. static PyMethodDef BufferSegment_methods[] = {
  269. {"tobytes", (PyCFunction)BufferSegment_tobytes, METH_NOARGS, NULL},
  270. {NULL, NULL}};
  271. static PyMemberDef BufferSegment_members[] = {
  272. {"offset", T_ULONGLONG, offsetof(ZstdBufferSegment, offset), READONLY,
  273. "offset of segment within parent buffer"},
  274. {NULL}};
  275. PyType_Slot ZstdBufferSegmentSlots[] = {
  276. {Py_tp_dealloc, BufferSegment_dealloc},
  277. {Py_sq_length, BufferSegment_length},
  278. #if PY_VERSION_HEX >= 0x03090000
  279. {Py_bf_getbuffer, BufferSegment_getbuffer},
  280. #endif
  281. {Py_tp_methods, BufferSegment_methods},
  282. {Py_tp_members, BufferSegment_members},
  283. {Py_tp_new, PyType_GenericNew},
  284. {0, NULL},
  285. };
  286. PyType_Spec ZstdBufferSegmentSpec = {
  287. "zstd.BufferSegment",
  288. sizeof(ZstdBufferSegment),
  289. 0,
  290. Py_TPFLAGS_DEFAULT,
  291. ZstdBufferSegmentSlots,
  292. };
  293. PyTypeObject *ZstdBufferSegmentType;
  294. static void
  295. BufferWithSegmentsCollection_dealloc(ZstdBufferWithSegmentsCollection *self) {
  296. Py_ssize_t i;
  297. if (self->firstElements) {
  298. PyMem_Free(self->firstElements);
  299. self->firstElements = NULL;
  300. }
  301. if (self->buffers) {
  302. for (i = 0; i < self->bufferCount; i++) {
  303. Py_CLEAR(self->buffers[i]);
  304. }
  305. PyMem_Free(self->buffers);
  306. self->buffers = NULL;
  307. }
  308. PyObject_Del(self);
  309. }
  310. static int
  311. BufferWithSegmentsCollection_init(ZstdBufferWithSegmentsCollection *self,
  312. PyObject *args) {
  313. Py_ssize_t size;
  314. Py_ssize_t i;
  315. Py_ssize_t offset = 0;
  316. size = PyTuple_Size(args);
  317. if (-1 == size) {
  318. return -1;
  319. }
  320. if (0 == size) {
  321. PyErr_SetString(PyExc_ValueError, "must pass at least 1 argument");
  322. return -1;
  323. }
  324. for (i = 0; i < size; i++) {
  325. PyObject *item = PyTuple_GET_ITEM(args, i);
  326. if (!PyObject_TypeCheck(item, ZstdBufferWithSegmentsType)) {
  327. PyErr_SetString(PyExc_TypeError,
  328. "arguments must be BufferWithSegments instances");
  329. return -1;
  330. }
  331. if (0 == ((ZstdBufferWithSegments *)item)->segmentCount ||
  332. 0 == ((ZstdBufferWithSegments *)item)->dataSize) {
  333. PyErr_SetString(PyExc_ValueError,
  334. "ZstdBufferWithSegments cannot be empty");
  335. return -1;
  336. }
  337. }
  338. self->buffers = PyMem_Malloc(size * sizeof(ZstdBufferWithSegments *));
  339. if (NULL == self->buffers) {
  340. PyErr_NoMemory();
  341. return -1;
  342. }
  343. self->firstElements = PyMem_Malloc(size * sizeof(Py_ssize_t));
  344. if (NULL == self->firstElements) {
  345. PyMem_Free(self->buffers);
  346. self->buffers = NULL;
  347. PyErr_NoMemory();
  348. return -1;
  349. }
  350. self->bufferCount = size;
  351. for (i = 0; i < size; i++) {
  352. ZstdBufferWithSegments *item =
  353. (ZstdBufferWithSegments *)PyTuple_GET_ITEM(args, i);
  354. self->buffers[i] = item;
  355. Py_INCREF(item);
  356. if (i > 0) {
  357. self->firstElements[i - 1] = offset;
  358. }
  359. offset += item->segmentCount;
  360. }
  361. self->firstElements[size - 1] = offset;
  362. return 0;
  363. }
  364. static PyObject *
  365. BufferWithSegmentsCollection_size(ZstdBufferWithSegmentsCollection *self) {
  366. Py_ssize_t i;
  367. Py_ssize_t j;
  368. unsigned long long size = 0;
  369. for (i = 0; i < self->bufferCount; i++) {
  370. for (j = 0; j < self->buffers[i]->segmentCount; j++) {
  371. size += self->buffers[i]->segments[j].length;
  372. }
  373. }
  374. return PyLong_FromUnsignedLongLong(size);
  375. }
  376. Py_ssize_t
  377. BufferWithSegmentsCollection_length(ZstdBufferWithSegmentsCollection *self) {
  378. return self->firstElements[self->bufferCount - 1];
  379. }
  380. static ZstdBufferSegment *
  381. BufferWithSegmentsCollection_item(ZstdBufferWithSegmentsCollection *self,
  382. Py_ssize_t i) {
  383. Py_ssize_t bufferOffset;
  384. if (i < 0) {
  385. PyErr_SetString(PyExc_IndexError, "offset must be non-negative");
  386. return NULL;
  387. }
  388. if (i >= BufferWithSegmentsCollection_length(self)) {
  389. PyErr_Format(PyExc_IndexError, "offset must be less than %zd",
  390. BufferWithSegmentsCollection_length(self));
  391. return NULL;
  392. }
  393. for (bufferOffset = 0; bufferOffset < self->bufferCount; bufferOffset++) {
  394. Py_ssize_t offset = 0;
  395. if (i < self->firstElements[bufferOffset]) {
  396. if (bufferOffset > 0) {
  397. offset = self->firstElements[bufferOffset - 1];
  398. }
  399. return BufferWithSegments_item(self->buffers[bufferOffset],
  400. i - offset);
  401. }
  402. }
  403. PyErr_SetString(ZstdError,
  404. "error resolving segment; this should not happen");
  405. return NULL;
  406. }
  407. static PyMethodDef BufferWithSegmentsCollection_methods[] = {
  408. {"size", (PyCFunction)BufferWithSegmentsCollection_size, METH_NOARGS,
  409. PyDoc_STR("total size in bytes of all segments")},
  410. {NULL, NULL}};
  411. PyType_Slot ZstdBufferWithSegmentsCollectionSlots[] = {
  412. {Py_tp_dealloc, BufferWithSegmentsCollection_dealloc},
  413. {Py_sq_length, BufferWithSegmentsCollection_length},
  414. {Py_sq_item, BufferWithSegmentsCollection_item},
  415. {Py_tp_methods, BufferWithSegmentsCollection_methods},
  416. {Py_tp_init, BufferWithSegmentsCollection_init},
  417. {Py_tp_new, PyType_GenericNew},
  418. {0, NULL},
  419. };
  420. PyType_Spec ZstdBufferWithSegmentsCollectionSpec = {
  421. "zstd.BufferWithSegmentsCollection",
  422. sizeof(ZstdBufferWithSegmentsCollection),
  423. 0,
  424. Py_TPFLAGS_DEFAULT,
  425. ZstdBufferWithSegmentsCollectionSlots,
  426. };
  427. PyTypeObject *ZstdBufferWithSegmentsCollectionType;
  428. void bufferutil_module_init(PyObject *mod) {
  429. ZstdBufferWithSegmentsType =
  430. (PyTypeObject *)PyType_FromSpec(&ZstdBufferWithSegmentsSpec);
  431. #if PY_VERSION_HEX < 0x03090000
  432. ZstdBufferWithSegmentsType->tp_as_buffer = &BufferWithSegments_as_buffer;
  433. #endif
  434. if (PyType_Ready(ZstdBufferWithSegmentsType) < 0) {
  435. return;
  436. }
  437. Py_INCREF(ZstdBufferWithSegmentsType);
  438. PyModule_AddObject(mod, "BufferWithSegments",
  439. (PyObject *)ZstdBufferWithSegmentsType);
  440. ZstdBufferSegmentsType =
  441. (PyTypeObject *)PyType_FromSpec(&ZstdBufferSegmentsSpec);
  442. #if PY_VERSION_HEX < 0x03090000
  443. ZstdBufferSegmentsType->tp_as_buffer = &BufferSegments_as_buffer;
  444. #endif
  445. if (PyType_Ready(ZstdBufferSegmentsType) < 0) {
  446. return;
  447. }
  448. Py_INCREF(ZstdBufferSegmentsType);
  449. PyModule_AddObject(mod, "BufferSegments",
  450. (PyObject *)ZstdBufferSegmentsType);
  451. ZstdBufferSegmentType =
  452. (PyTypeObject *)PyType_FromSpec(&ZstdBufferSegmentSpec);
  453. #if PY_VERSION_HEX < 0x03090000
  454. ZstdBufferSegmentType->tp_as_buffer = &BufferSegment_as_buffer;
  455. #endif
  456. if (PyType_Ready(ZstdBufferSegmentType) < 0) {
  457. return;
  458. }
  459. Py_INCREF(ZstdBufferSegmentType);
  460. PyModule_AddObject(mod, "BufferSegment", (PyObject *)ZstdBufferSegmentType);
  461. ZstdBufferWithSegmentsCollectionType =
  462. (PyTypeObject *)PyType_FromSpec(&ZstdBufferWithSegmentsCollectionSpec);
  463. if (PyType_Ready(ZstdBufferWithSegmentsCollectionType) < 0) {
  464. return;
  465. }
  466. Py_INCREF(ZstdBufferWithSegmentsCollectionType);
  467. PyModule_AddObject(mod, "BufferWithSegmentsCollection",
  468. (PyObject *)ZstdBufferWithSegmentsCollectionType);
  469. }