-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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: intermittent compilation errors #8441
Labels
Milestone
Comments
The issue here seems to be that cgo indeterminately writes _Ctype_struct_outer_t's "a" field as having either type "*_Ctype_inner" or "*_Ctype_struct___0", whereas "func doSomething(inner *C.inner)" is always being rewritten as "func doSomething(inner *_Ctype_struct___0)". The indeterminism seems to originate from GCC: over several runs of "go tool cgo main.go", when I get a different _cgo_gotypes.go file, I also get a different _cgo_.o file with slightly different DWARF debugging info. Attached the two _cgo_.o files, and here's the diff -u of their respective readelf --debug-dump=info outputs: --- _cgo_inner.o.dump 2014-08-04 14:32:45.067470563 -0700 +++ _cgo_type_struct___0.o.dump 2014-08-04 14:32:56.067652807 -0700 @@ -103,31 +103,31 @@ <be> DW_AT_name : (indirect string, offset: 0x65): __cgo__0 <c2> DW_AT_decl_file : 1 <c3> DW_AT_decl_line : 30 - <c4> DW_AT_type : <0x63> + <c4> DW_AT_type : <0xd3> <c8> DW_AT_external : 1 <c9> DW_AT_location : 9 byte block: 3 8 0 0 0 0 0 0 0 (DW_OP_addr: 8) - <1><d3>: Abbrev Number: 9 (DW_TAG_variable) - <d4> DW_AT_name : (indirect string, offset: 0x6e): __cgo__1 - <d8> DW_AT_decl_file : 1 - <d9> DW_AT_decl_line : 31 - <da> DW_AT_type : <0xe9> - <de> DW_AT_external : 1 - <df> DW_AT_location : 9 byte block: 3 8 0 0 0 0 0 0 0 (DW_OP_addr: 8) - <1><e9>: Abbrev Number: 6 (DW_TAG_pointer_type) - <ea> DW_AT_byte_size : 8 - <eb> DW_AT_type : <0x19> + <1><d3>: Abbrev Number: 6 (DW_TAG_pointer_type) + <d4> DW_AT_byte_size : 8 + <d5> DW_AT_type : <0x19> + <1><d9>: Abbrev Number: 9 (DW_TAG_variable) + <da> DW_AT_name : (indirect string, offset: 0x6e): __cgo__1 + <de> DW_AT_decl_file : 1 + <df> DW_AT_decl_line : 31 + <e0> DW_AT_type : <0x63> + <e4> DW_AT_external : 1 + <e5> DW_AT_location : 9 byte block: 3 8 0 0 0 0 0 0 0 (DW_OP_addr: 8) <1><ef>: Abbrev Number: 9 (DW_TAG_variable) <f0> DW_AT_name : (indirect string, offset: 0x77): __cgo__2 <f4> DW_AT_decl_file : 1 <f5> DW_AT_decl_line : 32 - <f6> DW_AT_type : <0x63> + <f6> DW_AT_type : <0xd3> <fa> DW_AT_external : 1 <fb> DW_AT_location : 9 byte block: 3 8 0 0 0 0 0 0 0 (DW_OP_addr: 8) <1><105>: Abbrev Number: 9 (DW_TAG_variable) <106> DW_AT_name : (indirect string, offset: 0x80): __cgo__3 <10a> DW_AT_decl_file : 1 <10b> DW_AT_decl_line : 33 - <10c> DW_AT_type : <0xe9> + <10c> DW_AT_type : <0x63> <110> DW_AT_external : 1 <111> DW_AT_location : 9 byte block: 3 8 0 0 0 0 0 0 0 (DW_OP_addr: 8) <1><11b>: Abbrev Number: 10 (DW_TAG_array_type) Attachments:
|
Adding -debug-gcc=true, I see cgo is actually the source of the indeterminism: @@ -614,10 +614,10 @@ _GoBytes_ GoBytes(void *p, int n); char *CString(_GoString_); void *_CMalloc(size_t); -__typeof__(outer) *__cgo__0; -__typeof__(inner) *__cgo__1; -__typeof__(outer) *__cgo__2; -__typeof__(inner) *__cgo__3; +__typeof__(inner) *__cgo__0; +__typeof__(outer) *__cgo__1; +__typeof__(inner) *__cgo__2; +__typeof__(outer) *__cgo__3; long long __cgodebug_data[] = { 0, 0, GCC determinately outputs one of the two .o files attached to #3 depending on the types assigned by cgo to __cgo__{0,1,2,3}. |
Here's what I believe the issue to be: In (*typeConv).Type(dwarf.Type, token.Pos), the case for dwarf.TypedefType overwrites t.Go if it notices that sub.Go is a struct/union type. However, because this is necessarily after the recursive call to Type(dt.Type, pos) to compute sub, the recursive call might have recursed back to this same DWARF type and saved the original t.Go value. E.g., both the dwarf.ArrayType and dwarf.PtrType cases save the sub.Go values they compute and won't be updated if the latter changes after returning. The easiest fix seems to be to hack the dwarf.TypedefType case to check if dt.Type is a dwarf.StructType, and compute the correct t.Go value before recursing. |
Thanks for looking at this. This bit of code in cgo is really bothering me now. We've had to change it several times, and it's not getting any simpler or easier to understand. Can you think of any way to make this simpler so that we can believe that it is correct? Status changed to Accepted. |
CL https://golang.org/cl/122850043 mentions this issue. |
Comment 8 by mdempsky@chromium.org: Sorry, was already working on uploading that CL before I saw your response. Off hand, no, I can't really think of how to simplify it, but I'll think some on that. I definitely agree that it's tricky, and it took me a long time to understand what was even going on here. :( |
Thinking about it some, I'd reason dwarf.PtrType is our best hope at breaking cycles. I don't think any of the analysis done in (*conv).Type(...) cares about the type pointed to, so we could just keep a queue of additional types that need resolving and any pointer types that refer to them that would need updating. And by making dwarf.PtrType non-recursive, we shouldn't be able to go into any Type loops, since types can only recurse a finite number of times without an indirection type. |
Updated the CL with a more general fix that also address issue #8368 by deferring resolution of DWARF types pointed to by a dwarf.PtrType record. |
This issue was closed by revision 0da4b2d. Status changed to Fixed. |
Issue #8463 has been merged into this issue. |
Issue #8463 has been merged into this issue. |
adg
added a commit
that referenced
this issue
May 11, 2015
««« CL 122850043 / 0015a2541545 cmd/cgo: fix recursive type mapping Instead of immediately completing pointer type mappings, add them to a queue to allow them to be completed later. This fixes issues caused by Type() returning arbitrary in-progress type mappings. Fixes #8368. Fixes #8441. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/122850043 »»» TBR=rsc R=rsc CC=golang-codereviews https://golang.org/cl/128940043
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jun 25, 2018
Instead of immediately completing pointer type mappings, add them to a queue to allow them to be completed later. This fixes issues caused by Type() returning arbitrary in-progress type mappings. Fixes golang#8368. Fixes golang#8441. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/122850043
wheatman
pushed a commit
to wheatman/go-akaros
that referenced
this issue
Jul 9, 2018
Instead of immediately completing pointer type mappings, add them to a queue to allow them to be completed later. This fixes issues caused by Type() returning arbitrary in-progress type mappings. Fixes golang#8368. Fixes golang#8441. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/122850043
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
by jvshahid:
The text was updated successfully, but these errors were encountered: