STINNER Victor <vstin...@python.org> added the comment:

Example:
---
struct Point { int x; int y; int z; };

int main()
{
    struct Point p = {1};
    return p.y;
}
---

gcc -O0 produces this machine code which sets p.y to 0 and p.z to 0:
---
Dump of assembler code for function main:
   0x0000000000401106 <+0>:     push   rbp
   0x0000000000401107 <+1>:     mov    rbp,rsp
   0x000000000040110a <+4>:     mov    QWORD PTR [rbp-0xc],0x0
   0x0000000000401112 <+12>:    mov    DWORD PTR [rbp-0x4],0x0
   0x0000000000401119 <+19>:    mov    DWORD PTR [rbp-0xc],0x1
   0x0000000000401120 <+26>:    mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000401123 <+29>:    pop    rbp
   0x0000000000401124 <+30>:    ret    
---

gcc -O3 heavily optimize the code, it always return 0, it doesn't return a 
random value from the stack:
---
(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000401020 <+0>:     xor    eax,eax
   0x0000000000401022 <+2>:     ret    
---

The "C99 Standard 6.7.8.21" says:

    If there are fewer initializers in a brace-enclosed list than there are 
elements or members of an aggregate, or fewer characters in a string literal 
used to initialize an array of known size than there are elements in the array, 
the remainder of the aggregate shall be initialized implicitly the same as 
objects that have static storage duration.

The C99 standard says that p.y and p.z must be set to 0.

I'm talking about the specific C syntax of a structure static initialization: 
"struct MyStruct x = {...};".


If "Py_buffer data = {NULL, NULL};" is allocated on the stack, all "data" 
Py_buffer members are set to 0 or NULL:

typedef struct bufferinfo {
    void *buf;
    PyObject *obj;        /* owned reference */
    Py_ssize_t len;
    Py_ssize_t itemsize;  /* This is Py_ssize_t so it can be
                             pointed to by strides in simple case.*/
    int readonly;
    int ndim;
    char *format;
    Py_ssize_t *shape;
    Py_ssize_t *strides;
    Py_ssize_t *suboffsets;
    void *internal;
} Py_buffer;


If we want to add a version member to this structure, I would suggest to 
enforce the usage of a static initialization macro or an initialization 
function, like:
  "Py_buffer data; PyBuffer_Init(&data);"
or
  "Py_buffer data = PyBuffer_STATIC_INIT;"

The problem of the macro is that it is not usable on Python extensions was are 
not written in C or C++ (or more generally to extensions which cannot use 
macros).

--

A different approach is to use an API which allocates a Py_buffer on the heap 
memory, so if the structure becomes larger tomorrow, an old built C extensions 
continues to work:

Py_buffer *data = PyBuffer_New();
// ... use *data ...
PyBuffer_Free(data);

PyBuffer_New() can initialize the version member and allocates the proper 
memory block size.

The best is if the "... use *data ..." part is only done with function calls :-)

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue45459>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to