LCOV - code coverage report
Current view: top level - Objects - picklebufobject.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 52 84 61.9 %
Date: 2022-07-20 13:12:14 Functions: 7 11 63.6 %
Branches: 18 32 56.2 %

           Branch data     Line data    Source code
       1                 :            : /* PickleBuffer object implementation */
       2                 :            : 
       3                 :            : #define PY_SSIZE_T_CLEAN
       4                 :            : #include "Python.h"
       5                 :            : #include <stddef.h>
       6                 :            : 
       7                 :            : typedef struct {
       8                 :            :     PyObject_HEAD
       9                 :            :     /* The view exported by the original object */
      10                 :            :     Py_buffer view;
      11                 :            :     PyObject *weakreflist;
      12                 :            : } PyPickleBufferObject;
      13                 :            : 
      14                 :            : /* C API */
      15                 :            : 
      16                 :            : PyObject *
      17                 :          0 : PyPickleBuffer_FromObject(PyObject *base)
      18                 :            : {
      19                 :          0 :     PyTypeObject *type = &PyPickleBuffer_Type;
      20                 :            :     PyPickleBufferObject *self;
      21                 :            : 
      22                 :          0 :     self = (PyPickleBufferObject *) type->tp_alloc(type, 0);
      23         [ #  # ]:          0 :     if (self == NULL) {
      24                 :          0 :         return NULL;
      25                 :            :     }
      26                 :          0 :     self->view.obj = NULL;
      27                 :          0 :     self->weakreflist = NULL;
      28         [ #  # ]:          0 :     if (PyObject_GetBuffer(base, &self->view, PyBUF_FULL_RO) < 0) {
      29                 :          0 :         Py_DECREF(self);
      30                 :          0 :         return NULL;
      31                 :            :     }
      32                 :          0 :     return (PyObject *) self;
      33                 :            : }
      34                 :            : 
      35                 :            : const Py_buffer *
      36                 :        110 : PyPickleBuffer_GetBuffer(PyObject *obj)
      37                 :            : {
      38                 :        110 :     PyPickleBufferObject *self = (PyPickleBufferObject *) obj;
      39                 :            : 
      40         [ -  + ]:        110 :     if (!PyPickleBuffer_Check(obj)) {
      41                 :          0 :         PyErr_Format(PyExc_TypeError,
      42                 :            :                      "expected PickleBuffer, %.200s found",
      43                 :          0 :                      Py_TYPE(obj)->tp_name);
      44                 :          0 :         return NULL;
      45                 :            :     }
      46         [ -  + ]:        110 :     if (self->view.obj == NULL) {
      47                 :          0 :         PyErr_SetString(PyExc_ValueError,
      48                 :            :                         "operation forbidden on released PickleBuffer object");
      49                 :          0 :         return NULL;
      50                 :            :     }
      51                 :        110 :     return &self->view;
      52                 :            : }
      53                 :            : 
      54                 :            : int
      55                 :          0 : PyPickleBuffer_Release(PyObject *obj)
      56                 :            : {
      57                 :          0 :     PyPickleBufferObject *self = (PyPickleBufferObject *) obj;
      58                 :            : 
      59         [ #  # ]:          0 :     if (!PyPickleBuffer_Check(obj)) {
      60                 :          0 :         PyErr_Format(PyExc_TypeError,
      61                 :            :                      "expected PickleBuffer, %.200s found",
      62                 :          0 :                      Py_TYPE(obj)->tp_name);
      63                 :          0 :         return -1;
      64                 :            :     }
      65                 :          0 :     PyBuffer_Release(&self->view);
      66                 :          0 :     return 0;
      67                 :            : }
      68                 :            : 
      69                 :            : static PyObject *
      70                 :        371 : picklebuf_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
      71                 :            : {
      72                 :            :     PyPickleBufferObject *self;
      73                 :            :     PyObject *base;
      74                 :        371 :     char *keywords[] = {"", NULL};
      75                 :            : 
      76         [ +  + ]:        371 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PickleBuffer",
      77                 :            :                                      keywords, &base)) {
      78                 :          1 :         return NULL;
      79                 :            :     }
      80                 :            : 
      81                 :        370 :     self = (PyPickleBufferObject *) type->tp_alloc(type, 0);
      82         [ -  + ]:        370 :     if (self == NULL) {
      83                 :          0 :         return NULL;
      84                 :            :     }
      85                 :        370 :     self->view.obj = NULL;
      86                 :        370 :     self->weakreflist = NULL;
      87         [ +  + ]:        370 :     if (PyObject_GetBuffer(base, &self->view, PyBUF_FULL_RO) < 0) {
      88                 :          2 :         Py_DECREF(self);
      89                 :          2 :         return NULL;
      90                 :            :     }
      91                 :        368 :     return (PyObject *) self;
      92                 :            : }
      93                 :            : 
      94                 :            : static int
      95                 :          2 : picklebuf_traverse(PyPickleBufferObject *self, visitproc visit, void *arg)
      96                 :            : {
      97   [ +  -  -  + ]:          2 :     Py_VISIT(self->view.obj);
      98                 :          2 :     return 0;
      99                 :            : }
     100                 :            : 
     101                 :            : static int
     102                 :          0 : picklebuf_clear(PyPickleBufferObject *self)
     103                 :            : {
     104                 :          0 :     PyBuffer_Release(&self->view);
     105                 :          0 :     return 0;
     106                 :            : }
     107                 :            : 
     108                 :            : static void
     109                 :        370 : picklebuf_dealloc(PyPickleBufferObject *self)
     110                 :            : {
     111                 :        370 :     PyObject_GC_UnTrack(self);
     112         [ -  + ]:        370 :     if (self->weakreflist != NULL)
     113                 :          0 :         PyObject_ClearWeakRefs((PyObject *) self);
     114                 :        370 :     PyBuffer_Release(&self->view);
     115                 :        370 :     Py_TYPE(self)->tp_free((PyObject *) self);
     116                 :        370 : }
     117                 :            : 
     118                 :            : /* Buffer API */
     119                 :            : 
     120                 :            : static int
     121                 :        317 : picklebuf_getbuf(PyPickleBufferObject *self, Py_buffer *view, int flags)
     122                 :            : {
     123         [ +  + ]:        317 :     if (self->view.obj == NULL) {
     124                 :          1 :         PyErr_SetString(PyExc_ValueError,
     125                 :            :                         "operation forbidden on released PickleBuffer object");
     126                 :          1 :         return -1;
     127                 :            :     }
     128                 :        316 :     return PyObject_GetBuffer(self->view.obj, view, flags);
     129                 :            : }
     130                 :            : 
     131                 :            : static void
     132                 :          0 : picklebuf_releasebuf(PyPickleBufferObject *self, Py_buffer *view)
     133                 :            : {
     134                 :            :     /* Since our bf_getbuffer redirects to the original object, this
     135                 :            :      * implementation is never called.  It only exists to signal that
     136                 :            :      * buffers exported by PickleBuffer have non-trivial releasing
     137                 :            :      * behaviour (see check in Python/getargs.c).
     138                 :            :      */
     139                 :          0 : }
     140                 :            : 
     141                 :            : static PyBufferProcs picklebuf_as_buffer = {
     142                 :            :     .bf_getbuffer = (getbufferproc) picklebuf_getbuf,
     143                 :            :     .bf_releasebuffer = (releasebufferproc) picklebuf_releasebuf,
     144                 :            : };
     145                 :            : 
     146                 :            : /* Methods */
     147                 :            : 
     148                 :            : static PyObject *
     149                 :        293 : picklebuf_raw(PyPickleBufferObject *self, PyObject *Py_UNUSED(ignored))
     150                 :            : {
     151         [ +  + ]:        293 :     if (self->view.obj == NULL) {
     152                 :          1 :         PyErr_SetString(PyExc_ValueError,
     153                 :            :                         "operation forbidden on released PickleBuffer object");
     154                 :          1 :         return NULL;
     155                 :            :     }
     156         [ +  - ]:        292 :     if (self->view.suboffsets != NULL
     157         [ +  + ]:        292 :         || !PyBuffer_IsContiguous(&self->view, 'A')) {
     158                 :          2 :         PyErr_SetString(PyExc_BufferError,
     159                 :            :                         "cannot extract raw buffer from non-contiguous buffer");
     160                 :          2 :         return NULL;
     161                 :            :     }
     162                 :        290 :     PyObject *m = PyMemoryView_FromObject((PyObject *) self);
     163         [ -  + ]:        290 :     if (m == NULL) {
     164                 :          0 :         return NULL;
     165                 :            :     }
     166                 :        290 :     PyMemoryViewObject *mv = (PyMemoryViewObject *) m;
     167                 :            :     assert(mv->view.suboffsets == NULL);
     168                 :            :     /* Mutate memoryview instance to make it a "raw" memoryview */
     169                 :        290 :     mv->view.format = "B";
     170                 :        290 :     mv->view.ndim = 1;
     171                 :        290 :     mv->view.itemsize = 1;
     172                 :            :     /* shape = (length,) */
     173                 :        290 :     mv->view.shape = &mv->view.len;
     174                 :            :     /* strides = (1,) */
     175                 :        290 :     mv->view.strides = &mv->view.itemsize;
     176                 :            :     /* Fix memoryview state flags */
     177                 :            :     /* XXX Expose memoryobject.c's init_flags() instead? */
     178                 :        290 :     mv->flags = _Py_MEMORYVIEW_C | _Py_MEMORYVIEW_FORTRAN;
     179                 :        290 :     return m;
     180                 :            : }
     181                 :            : 
     182                 :            : PyDoc_STRVAR(picklebuf_raw_doc,
     183                 :            : "raw($self, /)\n--\n\
     184                 :            : \n\
     185                 :            : Return a memoryview of the raw memory underlying this buffer.\n\
     186                 :            : Will raise BufferError is the buffer isn't contiguous.");
     187                 :            : 
     188                 :            : static PyObject *
     189                 :          3 : picklebuf_release(PyPickleBufferObject *self, PyObject *Py_UNUSED(ignored))
     190                 :            : {
     191                 :          3 :     PyBuffer_Release(&self->view);
     192                 :          3 :     Py_RETURN_NONE;
     193                 :            : }
     194                 :            : 
     195                 :            : PyDoc_STRVAR(picklebuf_release_doc,
     196                 :            : "release($self, /)\n--\n\
     197                 :            : \n\
     198                 :            : Release the underlying buffer exposed by the PickleBuffer object.");
     199                 :            : 
     200                 :            : static PyMethodDef picklebuf_methods[] = {
     201                 :            :     {"raw",     (PyCFunction) picklebuf_raw,     METH_NOARGS, picklebuf_raw_doc},
     202                 :            :     {"release", (PyCFunction) picklebuf_release, METH_NOARGS, picklebuf_release_doc},
     203                 :            :     {NULL,      NULL}
     204                 :            : };
     205                 :            : 
     206                 :            : PyTypeObject PyPickleBuffer_Type = {
     207                 :            :     PyVarObject_HEAD_INIT(NULL, 0)
     208                 :            :     .tp_name = "pickle.PickleBuffer",
     209                 :            :     .tp_doc = PyDoc_STR("Wrapper for potentially out-of-band buffers"),
     210                 :            :     .tp_basicsize = sizeof(PyPickleBufferObject),
     211                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
     212                 :            :     .tp_new = picklebuf_new,
     213                 :            :     .tp_dealloc = (destructor) picklebuf_dealloc,
     214                 :            :     .tp_traverse = (traverseproc) picklebuf_traverse,
     215                 :            :     .tp_clear = (inquiry) picklebuf_clear,
     216                 :            :     .tp_weaklistoffset = offsetof(PyPickleBufferObject, weakreflist),
     217                 :            :     .tp_as_buffer = &picklebuf_as_buffer,
     218                 :            :     .tp_methods = picklebuf_methods,
     219                 :            : };

Generated by: LCOV version 1.14