Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue 147: force-compute nested structs before parent structs #148

Merged
merged 1 commit into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/c/_cffi_backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -5238,6 +5238,13 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
&fbitsize, &foffset))
goto error;

if ((ftype->ct_flags & (CT_STRUCT | CT_UNION)) &&
!(ftype->ct_flags & CT_IS_OPAQUE)) {
/* force now the type of the nested field */
if (force_lazy_struct(ftype) < 0)
return NULL;
}

if (ftype->ct_size < 0) {
if ((ftype->ct_flags & CT_ARRAY) && fbitsize < 0
&& (i == nb_fields - 1 || foffset != -1)) {
Expand All @@ -5252,9 +5259,6 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
}
}
else if (ftype->ct_flags & (CT_STRUCT|CT_UNION)) {
if (force_lazy_struct(ftype) < 0) /* for CT_WITH_VAR_ARRAY */
return NULL;

/* GCC (or maybe C99) accepts var-sized struct fields that are not
the last field of a larger struct. That's why there is no
check here for "last field": we propagate the flag
Expand Down
2 changes: 1 addition & 1 deletion src/c/cdlopen.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ static PyObject *ffi_dlclose(PyObject *self, PyObject *args)

static Py_ssize_t cdl_4bytes(char *src)
{
/* read 4 bytes in little-endian order; return it as a signed integer */
/* read 4 bytes in big-endian order; return it as a signed integer */
signed char *ssrc = (signed char *)src;
unsigned char *usrc = (unsigned char *)src;
return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
Expand Down
30 changes: 30 additions & 0 deletions testing/cffi1/test_re_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,33 @@ def test_dlopen_handle():

err = lib1.dlclose(handle)
assert err == 0

def test_rec_structs_1():
ffi = FFI()
ffi.cdef("struct B { struct C* c; }; struct C { struct B b; };")
ffi.set_source('test_rec_structs_1', None)
ffi.emit_python_code(str(tmpdir.join('_rec_structs_1.py')))
#
if sys.version_info[:2] >= (3, 3):
import importlib
importlib.invalidate_caches() # issue 197, maybe
#
from _rec_structs_1 import ffi
# the following line used to raise TypeError
# unless preceeded by 'ffi.sizeof("struct C")'.
sz = ffi.sizeof("struct B")
assert sz == ffi.sizeof("int *")

def test_rec_structs_2():
ffi = FFI()
ffi.cdef("struct B { struct C* c; }; struct C { struct B b; };")
ffi.set_source('test_rec_structs_2', None)
ffi.emit_python_code(str(tmpdir.join('_rec_structs_2.py')))
#
if sys.version_info[:2] >= (3, 3):
import importlib
importlib.invalidate_caches() # issue 197, maybe
#
from _rec_structs_2 import ffi
sz = ffi.sizeof("struct C")
assert sz == ffi.sizeof("int *")
Loading