Better way to get size of packed c struct in go?

1,231 views
Skip to first unread message

jasdel

unread,
Jun 18, 2014, 4:40:30 AM6/18/14
to golan...@googlegroups.com
I'm working with a c structure which happens to be pack to two byte alignments in the library that cgo is linking against.  I noticed unsafe.Sizeof doesn't respect the packing, and will return the unpacked size of the structure.  As a workaround i've created mini helper C functions to return the size of a given type (http://play.golang.org/p/o3fSS5mUcp).  I'm curious if there is a better way to do this.

As an example gssapi on mac use #parama pack(2), all other platforms are not packed, of course.

    typedef struct gss_OID_desc_struct {
        OM_uint32 length;
        void *elements;
    } gss_OID_desc, *gss_OID; // 16 bytes from Go's unsafe.Sizeof(C.gss_OID_desc{}), but 12 bytes in c's sizeof(gss_OID_desc)

    typedef struct gss_OID_set_desc_struct  {
        size_t  count;
        gss_OID elements;
    } gss_OID_set_desc, *gss_OID_set;

The set's elements cannot be converted to a slice through reflection/unsafe.Pointer, because the slice header creation will think the gss_OID_desc type has a size of 16 bytes not 12, causing memory errors when used. So to move through the element list i need to do the following:

    /*
    ...
    int size_of_gss_OIB_set_desc() {
        return sizeof(gss_OID_desc);
    }

    */
    import "C"
    
    ...
    
var ptr unsafe.Pointer = unsafe.Pointer(set.elements)
for idx = 0; idx < set.count; idx++ {
elem = (C.gss_OID)(ptr)
     
// stuff ...
      
if idx < set.count {
ptr = unsafe.Pointer(uintptr(ptr) + uintptr(C.size_of_gss_OIB_set_desc()))
}
}

Any suggestions?

Cheers,
jasdel

Dave Cheney

unread,
Jun 18, 2014, 8:01:57 AM6/18/14
to golan...@googlegroups.com


On Wednesday, 18 June 2014 18:40:30 UTC+10, jasdel wrote:
I'm working with a c structure which happens to be pack to two byte alignments in the library that cgo is linking against.  I noticed unsafe.Sizeof doesn't respect the packing, and will return the unpacked size of the structure.  As a workaround i've created mini helper C functions to return the size of a given type (http://play.golang.org/p/o3fSS5mUcp).  I'm curious if there is a better way to do this.

As an example gssapi on mac use #parama pack(2), all other platforms are not packed, of course.

    typedef struct gss_OID_desc_struct {
        OM_uint32 length;
        void *elements;
    } gss_OID_desc, *gss_OID; // 16 bytes from Go's unsafe.Sizeof(C.gss_OID_desc{}), but 12 bytes in c's sizeof(gss_OID_desc)

Assuming you're using a 64bit platform Go will insert 4 bytes padding between length and *elements as *elements is a pointer and will be aligned on a 8 byte boundary.
 

    typedef struct gss_OID_set_desc_struct  {
        size_t  count;
        gss_OID elements;
    } gss_OID_set_desc, *gss_OID_set;

The set's elements cannot be converted to a slice through reflection/unsafe.Pointer, because the slice header creation will think the gss_OID_desc type has a size of 16 bytes not 12, causing memory errors when used. So to move through the element list i need to do the following:

    /*
    ...
    int size_of_gss_OIB_set_desc() {
        return sizeof(gss_OID_desc);
    }

    */
    import "C"
    
    ...
    
var ptr unsafe.Pointer = unsafe.Pointer(set.elements)
for idx = 0; idx < set.count; idx++ {
elem = (C.gss_OID)(ptr)
     
// stuff ...
      
if idx < set.count {
ptr = unsafe.Pointer(uintptr(ptr) + uintptr(C.size_of_gss_OIB_set_desc()))
}
}

Any suggestions?

 

Cheers,
jasdel
Reply all
Reply to author
Forward
0 new messages