1
0
mirror of https://github.com/golang/go synced 2024-11-23 07:50:05 -07:00

cmd/cgo: omit misaligned struct fields, like we omit bitfields

Fixes #7560.

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/96300045
This commit is contained in:
Russ Cox 2014-05-12 23:48:20 -04:00
parent 211618c26e
commit 2d1a9510ed
4 changed files with 60 additions and 3 deletions

View File

@ -52,5 +52,6 @@ func Test6390(t *testing.T) { test6390(t) }
func Test5986(t *testing.T) { test5986(t) }
func Test7665(t *testing.T) { test7665(t) }
func TestNaming(t *testing.T) { testNaming(t) }
func Test7560(t *testing.T) { test7560(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

View File

@ -0,0 +1,44 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cgotest
/*
#include <stdint.h>
typedef struct {
char x;
long y;
} __attribute__((__packed__)) misaligned;
int
offset7560(void)
{
return (uintptr_t)&((misaligned*)0)->y;
}
*/
import "C"
import (
"reflect"
"testing"
)
func test7560(t *testing.T) {
// some mingw don't implement __packed__ correctly.
if C.offset7560() != 1 {
t.Skip("C compiler did not pack struct")
}
// C.misaligned should have x but then a padding field to get to the end of the struct.
// There should not be a field named 'y'.
var v C.misaligned
rt := reflect.TypeOf(&v).Elem()
if rt.NumField() != 2 || rt.Field(0).Name != "x" || rt.Field(1).Name != "_" {
t.Errorf("unexpected fields in C.misaligned:\n")
for i := 0; i < rt.NumField(); i++ {
t.Logf("%+v\n", rt.Field(i))
}
}
}

View File

@ -68,6 +68,9 @@ Go references to C
Within the Go file, C's struct field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.
C struct fields that cannot be expressed in Go, such as bit fields
or misaligned data, are omitted in the Go struct, replaced by
appropriate padding to reach the next field or the end of the struct.
The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),

View File

@ -1499,7 +1499,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
t := c.Type(f.Type, pos)
tgo := t.Go
size := t.Size
talign := t.Align
if f.BitSize > 0 {
if f.BitSize%8 != 0 {
continue
@ -1512,8 +1512,17 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
name = "uint"
}
tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
talign = size
}
if talign > 0 && f.ByteOffset%talign != 0 {
// Drop misaligned fields, the same way we drop integer bit fields.
// The goal is to make available what can be made available.
// Otherwise one bad and unneeded field in an otherwise okay struct
// makes the whole program not compile. Much of the time these
// structs are in system headers that cannot be corrected.
continue
}
n := len(fld)
fld = fld[0 : n+1]
name := f.Name
@ -1528,8 +1537,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
buf.WriteString(" ")
buf.WriteString(name)
buf.WriteString("; ")
if t.Align > align {
align = t.Align
if talign > align {
align = talign
}
}
if off < dt.ByteSize {