1. Python CFFI
  2. Untitled project
  3. cffi
Issue #150 wontfix

structs with bit fields as arguments

Nickolas Fotopoulos
created an issue

I have run into "NotImplementedError: <blah>: cannot pass as argument or return value a struct with bit-fields" in fb_fill_type(). After studying the problem, I would guess that this is not implemented because so many aspects of bit-field binary representation are implementation-defined?

Given that we can call against libraries compiled with different compilers, but on the same cpu architecture, we will never swap endian-ness. So it seems like some kinds of bit-field args should be safe. For example, if the bit widths total to less than 8, we should be totally safe. If bit-fields never straddle multiples of 8, we should likewise be safe from changes in addressable storage unit.

Does this logic seem correct to you? If so, would you accept a patch that fills in the unimplemented part of fb_fill_type() with the restriction that no field shall straddle the boundaries defined by all multiples of 8 bits?

C99 spec: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf

Comments (5)

  1. Armin Rigo

    The original motivation for this restriction is that libffi doesn't support such calls. It's possible to work around it in a platform-specific manner, but not in general --- even if you add restrictions. (I assume you're not using verify() because it's easy to work around the problem there.)

    Here is why. I don't know exactly what your guess about the layout of bitfields is, but it is likely wrong --- like mine in the first versions :-) The exact details depend on the compiler and the platform, and cffi only implements it for MSVC and for GCC on a few common platforms. They are all different from each other. See the tests for examples that differ (including some where all fields fit nicely inside 8 bits).

    The exact ABI details of how to do the call may in theory depend from the fact that it's bitfields, so the fact that it's missing from libffi is a blocker. Now in practice it might be possible to work around that fact by filling some integer fields of various sizes --- but this depends again on the platform.

    I would definitely prefer an implementation that guesses correctly for all common platforms (and leaving uncommon ones to whoever cares), rather than one that has artificial restrictions like multiples of 8 bits.

  2. Nickolas Fotopoulos reporter

    You give a fair analysis. I am unfamiliar with libffi, but it seems like this isn't going to magically be fixed any time soon. Thanks.

    I am using verify(), actually. What's the easy workaround? I'm quite new to cffi and don't have a well-developed bag of tricks yet. Would it be to declare a non-bit-fielded version of the struct and add a wrapper for the function I want to call that converts non-bit-fielded to bit-fielded before calling the true function of interest?

  3. Armin Rigo

    The trick is to add a wrapper, yes, but simply pass the structure by reference to the wrapper, which itself passes it by value to the real function:

    int myfoo(struct s *p) { return foo(*p); }

  4. Log in to comment