This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients Geoff.Clements, eryksun, meador.inge, pitrou
Date 2014-11-01.22:38:15
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1414881496.38.0.537491399427.issue22781@psf.upfronthosting.co.za>
In-reply-to
Content
ctypes doesn't always handle bitfields correctly. In particular it doesn't adapt the storage unit size when packed. A bitfield based on c_uint is always stored in 4 bytes, even if _pack_ is set to 1. This is MSVC rules, so all is well on Windows. 

For example, from ifo_types.h:

    typedef struct {
      unsigned int zero_1                    : 1;
      unsigned int multi_or_random_pgc_title : 1; /* 0: one sequential pgc title */
      unsigned int jlc_exists_in_cell_cmd    : 1;
      unsigned int jlc_exists_in_prepost_cmd : 1;
      unsigned int jlc_exists_in_button_cmd  : 1;
      unsigned int jlc_exists_in_tt_dom      : 1;
      unsigned int chapter_search_or_play    : 1; /* UOP 1 */
      unsigned int title_or_time_play        : 1; /* UOP 0 */
    } ATTRIBUTE_PACKED playback_type_t;

ctypeslib translates this as follows:

    class playback_type_t(Structure):
        pass
    playback_type_t._fields_ = [
        ('zero_1', c_uint, 1),
        ('multi_or_random_pgc_title', c_uint, 1),
        ('jlc_exists_in_cell_cmd', c_uint, 1),
        ('jlc_exists_in_prepost_cmd', c_uint, 1),
        ('jlc_exists_in_button_cmd', c_uint, 1),
        ('jlc_exists_in_tt_dom', c_uint, 1),
        ('chapter_search_or_play', c_uint, 1),
        ('title_or_time_play', c_uint, 1),
    ]

It doesn't set _pack_ = 1, but ctypes wouldn't use that to pack the c_uint bitfield anyway. It's 4 bytes, either way. MSVC agrees, even with #pragma pack(1). OTOH, with __attribute__((packed)), gcc packs the bitfield into a single byte. 

The incorrect packing (for gcc) of playback_type_t results in an incorrect offset for title_set_nr in title_info_t:

    class title_info_t(Structure):
        pass
    title_info_t._pack_ = 1
    title_info_t._fields_ = [
        ('pb_ty', playback_type_t),
        ('nr_of_angles', uint8_t),
        ('nr_of_ptts', uint16_t),
        ('parental_id', uint16_t),
        ('title_set_nr', uint8_t),
        ('vts_ttn', uint8_t),
        ('title_set_sector', uint32_t),
    ]

As a workaround for the immediate problem, on platforms that use gcc you can use c_uint8 in playback_type_t instead of c_uint. You'll want to verify other bitfields as well. I don't know about other compilers on other platforms. 

Working at the ABI level can be painful. Consider using CFFI's API level interface instead:

https://cffi.readthedocs.org
History
Date User Action Args
2014-11-01 22:38:16eryksunsetrecipients: + eryksun, pitrou, meador.inge, Geoff.Clements
2014-11-01 22:38:16eryksunsetmessageid: <1414881496.38.0.537491399427.issue22781@psf.upfronthosting.co.za>
2014-11-01 22:38:16eryksunlinkissue22781 messages
2014-11-01 22:38:15eryksuncreate