Skip to content

Commit eaa97fb

Browse files
cmd/cgo: don't translate bitfields into Go fields
The cgo tool would sometimes emit a bitfield at an offset that did not correspond to the C offset, such as for the example in the new test. Change-Id: I61b2ca10ee44a42f81c13ed12865f2060168fed5 Reviewed-on: https://go-review.googlesource.com/c/go/+/252378 Trust: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent b6dbaef commit eaa97fb

File tree

5 files changed

+75
-15
lines changed

5 files changed

+75
-15
lines changed

doc/go1.16.html

+10
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ <h4 id="all-pattern">The <code>all</code> pattern</h4>
8686
by <code>go</code> <code>mod</code> <code>vendor</code> since Go 1.11.
8787
</p>
8888

89+
<h3 id="cgo">Cgo</h3>
90+
91+
<p> <!-- CL 252378 -->
92+
The <a href="/cmd/cgo">cgo</a> tool will no longer try to translate
93+
C struct bitfields into Go struct fields, even if their size can be
94+
represented in Go. The order in which C bitfields appear in memory
95+
is implementation dependent, so in some cases the cgo tool produced
96+
results that were silently incorrect.
97+
</p>
98+
8999
<p>
90100
TODO
91101
</p>
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
//
5+
// +build ignore
6+
7+
package main
8+
9+
// This file tests that we don't generate an incorrect field location
10+
// for a bitfield that appears aligned.
11+
12+
/*
13+
struct bitfields {
14+
unsigned int B1 : 5;
15+
unsigned int B2 : 1;
16+
unsigned int B3 : 1;
17+
unsigned int B4 : 1;
18+
unsigned int Short1 : 16; // misaligned on 8 bit boundary
19+
unsigned int B5 : 1;
20+
unsigned int B6 : 1;
21+
unsigned int B7 : 1;
22+
unsigned int B8 : 1;
23+
unsigned int B9 : 1;
24+
unsigned int B10 : 3;
25+
unsigned int Short2 : 16; // alignment is OK
26+
unsigned int Short3 : 16; // alignment is OK
27+
};
28+
*/
29+
import "C"
30+
31+
type bitfields C.struct_bitfields

misc/cgo/testgodefs/testdata/main.go

+28
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
package main
66

7+
import (
8+
"fmt"
9+
"os"
10+
"reflect"
11+
)
12+
713
// Test that the struct field in anonunion.go was promoted.
814
var v1 T
915
var v2 = v1.L
@@ -23,4 +29,26 @@ var v7 = S{}
2329
var _ = issue38649{X: 0}
2430

2531
func main() {
32+
pass := true
33+
34+
// The Go translation of bitfields should not have any of the
35+
// bitfield types. The order in which bitfields are laid out
36+
// in memory is implementation defined, so we can't easily
37+
// know how a bitfield should correspond to a Go type, even if
38+
// it appears to be aligned correctly.
39+
bitfieldType := reflect.TypeOf(bitfields{})
40+
check := func(name string) {
41+
_, ok := bitfieldType.FieldByName(name)
42+
if ok {
43+
fmt.Fprintf(os.Stderr, "found unexpected bitfields field %s\n", name)
44+
pass = false
45+
}
46+
}
47+
check("Short1")
48+
check("Short2")
49+
check("Short3")
50+
51+
if !pass {
52+
os.Exit(1)
53+
}
2654
}

misc/cgo/testgodefs/testgodefs_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
// import "C" block. Add more tests here.
2020
var filePrefixes = []string{
2121
"anonunion",
22+
"bitfields",
2223
"issue8478",
2324
"fieldtypedef",
2425
"issue37479",

src/cmd/cgo/gcc.go

+5-15
Original file line numberDiff line numberDiff line change
@@ -2831,21 +2831,11 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
28312831
tgo := t.Go
28322832
size := t.Size
28332833
talign := t.Align
2834-
if f.BitSize > 0 {
2835-
switch f.BitSize {
2836-
case 8, 16, 32, 64:
2837-
default:
2838-
continue
2839-
}
2840-
size = f.BitSize / 8
2841-
name := tgo.(*ast.Ident).String()
2842-
if strings.HasPrefix(name, "int") {
2843-
name = "int"
2844-
} else {
2845-
name = "uint"
2846-
}
2847-
tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
2848-
talign = size
2834+
if f.BitOffset > 0 || f.BitSize > 0 {
2835+
// The layout of bitfields is implementation defined,
2836+
// so we don't know how they correspond to Go fields
2837+
// even if they are aligned at byte boundaries.
2838+
continue
28492839
}
28502840

28512841
if talign > 0 && f.ByteOffset%talign != 0 {

0 commit comments

Comments
 (0)