golang/go
View on GitHubcmd/cgo: miscalculates C array offset when C struct has __attribute__((__packed__))
Open
#46,675 opened on Jun 9, 2021
NeedsFixcompiler/runtimehelp wanted
Repository metrics
- Stars
- (133,883 stars)
- PR merge metrics
- (No merged PRs in 30d)
Description
What version of Go are you using (go version)?
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env)?
C compiler: gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 on Ubuntu 18.04
What did you do?
I execute go run x.go with the following input file:
package main
/*
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct P
{
uint64_t a;
struct {
uint64_t b;
uint8_t c;
} __attribute__((__packed__));
} P;
typedef struct Q
{
P d[3];
} Q;
void show(const Q* q)
{
printf("sizeof(P)=%zu sizeof(Q)=%zu\n", sizeof(P), sizeof(Q));
for (int i = 0; i < sizeof(q->d) / sizeof(q->d[0]); ++i) {
const P* p = &q->d[i];
printf("[%d] a=%016"PRIx64" b=%016"PRIx64" c=%02"PRIx8"\n", i, p->a, p->b, p->c);
}
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
var q C.Q
q.d[0].a = 0xA0A0A0A0A0A0A0A0
q.d[1].a = 0xA1A1A1A1A1A1A1A1
q.d[2].a = 0xA2A2A2A2A2A2A2A2
fmt.Println(unsafe.Sizeof(C.P{}), unsafe.Sizeof(C.Q{}))
fmt.Println(q)
C.show(&q)
}
What did you expect to see?
$ go run x.go
24 72
{[{11574427654092267680 {0 0} [0 0 0 0 0 0 0]} {11646767826930344353 {0 0} [0 0 0 0 0 0 0]} {11719107999768421026 {0 0} [0 0 0 0 0 0 0]}]}
sizeof(P)=24 sizeof(Q)=72
[0] a=a0a0a0a0a0a0a0a0 b=0000000000000000 c=00
[1] a=a1a1a1a1a1a1a1a1 b=0000000000000000 c=00
[2] a=a2a2a2a2a2a2a2a2 b=0000000000000000 c=00
What did you see instead?
$ go run x.go
32 96
{[{11574427654092267680 {0 0} [0 0 0 0 0 0 0]} {11646767826930344353 {0 0} [0 0 0 0 0 0 0]} {11719107999768421026 {0 0} [0 0 0 0 0 0 0]}]}
sizeof(P)=24 sizeof(Q)=72
[0] a=a0a0a0a0a0a0a0a0 b=0000000000000000 c=00
[1] a=0000000000000000 b=a1a1a1a1a1a1a1a1 c=00
[2] a=0000000000000000 b=0000000000000000 c=a2
Notice that cgo and gcc reports different size for C structs.
Additional Information
If struct P is changed to:
typedef struct P
{
uint64_t a;
uint64_t b;
uint8_t c;
} __attribute__((__packed__)) P;
It also causes cgo to misbehave:
$ go run x.go
24 72
{[{11574427654092267680 0 0} {11646767826930344353 0 0} {11719107999768421026 0 0}]}
sizeof(P)=17 sizeof(Q)=51
[0] a=a0a0a0a0a0a0a0a0 b=0000000000000000 c=00
[1] a=a100000000000000 b=00a1a1a1a1a1a1a1 c=00
[2] a=0000000000000000 b=a2a2000000000000 c=a2