Repository navigation
ffi: build without libffi complex number types - #503
Merged
Merged
Conversation
A complex number is represented as a CT_ARRAY of two reals, so the width of the value decides which pair of conversions converts it back. Any width other than a pair of long doubles was taken for a pair of floats, which converted the halves through conversions of the wrong type. Those conversions are themselves complex, so they re-entered this function with the same width and exhausted the stack. Accept the three widths libffi provides complex types for and report an unknown width instead. The other widths need a representation which does not exist yet, so guessing one of the existing ones only turns a diagnostic into a recursion. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Two defects kept structures from working as function arguments or return values. The predefined alignment was taken from the CType as is, but that field holds a base 2 logarithm, so libffi saw 3 instead of 8 for a structure of doubles. It now receives the plain byte value. More seriously, no member vector was built at all. libffi needs one for a FFI_TYPE_STRUCT: with a NULL vector initialize_aggregate() is unable to derive size and alignment and ffi_prep_cif() ends up dereferencing the missing members, which crashed the process. The vector is now built from the members of the type, representing bitfields by their storage class and function members by a pointer. Because a union shares its storage, while a member vector describes consecutive members whose sizes add up, no descriptor is able to pass a union the way the ABI passes one. Such declarations are rejected now instead of silently passing bogus values. Structures passed by value, including nested ones and ones carrying bitfields, now arrive at the callee as the ABI lays them out. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Handing a closure's type descriptor storage to uc_ctype_to_ffi_type() as the place to describe a type in kept structures from working as closure arguments. The storage holds one entry per top level type, so a structure was described through the entry of whichever type was converted into it before, which left it with that type's size and alignment. ffi_prep_cif() then placed the argument accordingly and crashed while reading the descriptor. The storage existed to avoid allocating descriptors separately, which uc_ctype_to_ffi_type() does not do anymore, so it is gone and the context keeps pointers only. Describing a type properly made its lifetime worth getting right, which it was not. Argument type descriptors were released by comparing them against FFI_TYPE_STRUCT, a test that never matched as they refer to libffi's predefined descriptors, so the descriptors synthesized for structures leaked on every call. A closure leaks them too, as it is invoked long after the call which created it. Tell the two kinds apart by comparing a descriptor against the addresses of the predefined ones, which form a closed set, and release everything else along its owner: the descriptors of stack temporaries once the call returned, those of a closure along the closure. Comparing against libffi's predefined descriptors is what tells the two kinds apart, since inspecting a descriptor cannot: the kind of a structure is FFI_TYPE_VOID until libffi has filled it in, and its size is set from the type, so a structure of two 64 bit integers would look exactly like ffi_type_longdouble and be released twice. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
libffi declares ffi_type_complex_float and ffi_type_complex_double only when the backend defines FFI_TARGET_HAS_COMPLEX_TYPE, which powerpc does not, so the module failed to build for that target: lib/ffi/ffi.c: error: 'ffi_type_complex_double' undeclared Detect the types while configuring and reject complex declarations at runtime where they are unavailable. A complex value cannot be described as a struct of two reals instead: libffi passes such a description differently than the predefined type, so calls would end up passing bogus values. Complex numbers are rarely declared, while a build failing on an unrelated declaration is not, which makes the exception the better trade off. The set of predefined descriptors grows by the complex ones where libffi provides them, since a synthesized descriptor must never be mistaken for one. Fixes: #502 Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
libffi only declares
ffi_type_complex_floatandffi_type_complex_doublewhen the backend defines
FFI_TARGET_HAS_COMPLEX_TYPE, which severalOpenWrt targets (powerpc, loongarch, riscv, ...) do not, so the module
failed to build:
This branch detects the types at configure time and rejects complex
declarations at runtime where they are unavailable, and carries a few
related ffi fixes:
Detect ffi complex types during configuration; a synthesized struct
of two reals cannot be used instead since libffi passes it
differently. Adds the predefined complex descriptors to the
recognized set where libffi provides them.
Unknown widths were misread as float pairs, whose conversions re-enter
the function with the same width and exhausted the stack. Accept the
three widths libffi provides and report unknown widths.
Alignment was passed as the base-2 logarithm stored in the CType, and
the member vector required by FFI_TYPE_STRUCT was never built, so
ffi_prep_cif() crashed. Build the vector from the members and reject
unions, which no descriptor can represent.
Closure argument types were described through stale descriptor
storage, and synthesized struct descriptors were leaked on every call
and per closure since the FFI_TYPE_STRUCT comparison never matched.
Track descriptors against libffi's predefined set and release them
along their owner.
Adds testcases for structures passed by value, struct arguments in
closures, complex number conversion errors, and complex number types.
Fixes: #502