Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/cgo: "struct size calculation error" build error when returning id type from cgo to Go on Darwin. #12065

Closed
dmitshur opened this issue Aug 7, 2015 · 2 comments

Comments

@dmitshur
Copy link
Member

commented Aug 7, 2015

Standard Questions

What version of Go are you using (go version)?

go version go1.5rc1 darwin/amd64

What operating system and processor architecture are you using?

OS X Yosemite Version 10.10.4 (14E46)

What did you do?

Here's a small reproduce case. Create a main.go file in an empty folder:

// +build darwin

package main

/*
#cgo CFLAGS: -x objective-c

id foo() {
    return 0;
}
*/
import "C"

import "fmt"

func main() {
    fmt.Println(C.foo())
}

Then run:

go build

What did you expect to see?

No output, because the build should be successful.

What did you see instead?

A failure to build, with the following error:

./main.go:17:14: struct size calculation error off=8 bytesize=0

Notes

I'm not an expert on Objective-C, so this may be a user error. But from what I can tell, it looks like a longstanding bug with cgo.

Objective-C seems to have a predeclared type id. I have seen headers (in external code) that include the following:

#if defined(__OBJC__)
 #import <Cocoa/Cocoa.h>
#else
 typedef void* id;
#endif

Which leads me to think id type is similar to a void pointer.

When building the program below, I can tell that __OBJC__ is set. I can also tell id is declared even if I don't import <Cocoa/Cocoa.h>, because if I change the type from id to idx, I get a clang error:

./main.go:8:1: error: unknown type name 'idx'; did you mean 'id'?
idx foo() {
^~~
id
note: 'id' declared here
1 error generated.

Adding #import <Cocoa/Cocoa.h> or typedef void* id; does not make any difference on the error.

However, using a different type name (e.g., idx) and doing typedef void* idx; results in a successful compilation.

This issue might be related to #3505 which is the only remaining reported unresolved issue with a similar struct size calculation error error message.

Original issue is go-gl/glfw#136.

@mikioh mikioh changed the title cgo: "struct size calculation error" build error when returning id type from cgo to Go on Darwin. cmd/cgo: "struct size calculation error" build error when returning id type from cgo to Go on Darwin. Aug 7, 2015

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Aug 7, 2015

The error means that the debug info shows that the debug info defines id as a struct that has size 0 but has an 8 byte field. That is clearly wrong. I can recreate the problem using clang/LLVM 3.4 on GNU/Linux (your test case works fine with GCC). Using readelf --debug on the object file generated by LLVM, I see this:

<1><79>: Abbrev Number: 10 (DW_TAG_typedef)
    <7a>   DW_AT_type        : <0x84>   
    <7e>   DW_AT_name        : (indirect string, offset: 0xa1): id      
    <82>   DW_AT_decl_file   : 2        
    <83>   DW_AT_decl_line   : 6        

<1><84>: Abbrev Number: 7 (DW_TAG_pointer_type)
<85> DW_AT_type : <0x89>
<1><89>: Abbrev Number: 11 (DW_TAG_structure_type)
<8a> DW_AT_name : (indirect string, offset: 0x95): objc_object
<8e> DW_AT_byte_size : 0
<2><8f>: Abbrev Number: 12 (DW_TAG_member)
<90> DW_AT_name : (indirect string, offset: 0x86): isa
<94> DW_AT_type : <0x9b>
<98> DW_AT_data_member_location: 0
<99> DW_AT_accessibility: 1 (public)
<2><9a>: Abbrev Number: 0
<1><9b>: Abbrev Number: 7 (DW_TAG_pointer_type)
<9c> DW_AT_type : <0xa0>
<1>: Abbrev Number: 13 (DW_TAG_structure_type)
DW_AT_name : (indirect string, offset: 0x8a): objc_class
DW_AT_declaration : 1
<1>: Abbrev Number: 2 (DW_TAG_variable)
DW_AT_name : (indirect string, offset: 0xa4): __cgo__1

This says that id is a typedef for a pointer to the struct objc_object, and that objc_object has a size of 0 but has one member, isa, which is a pointer to the struct objc_class (the size of 0 can be seen at the line labeled 8e). So this debug info is incorrect: objc_object is 0 bytes but has a pointer field. The right fix would be to change LLVM to generate the correct debug info.

I can't think of a good way for cgo to handle this case. I think workarounds in the source code, as you suggest, is going to be your best bet. So I'm going to close this issue since it doesn't seem to be a problem we can fix in Go.

@dmitshur

This comment has been minimized.

Copy link
Member Author

commented Aug 7, 2015

Thank you for explaining that the problem lies in LLVM and not in Go/cgo.

@golang golang locked and limited conversation to collaborators Aug 8, 2016

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
3 participants
You can’t perform that action at this time.