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: intermittent compilation errors #8441

Closed
gopherbot opened this issue Jul 29, 2014 · 17 comments

Comments

@gopherbot
Copy link

commented Jul 29, 2014

by jvshahid:

What does 'go version' print?

Tried with go version go1.3 linux/amd64 and the latest committed change
go version devel +6125ea2b1dbf Tue Jul 29 15:18:01 2014 +0400 linux/amd64

What steps reproduce the problem?

If possible, include a link to a program on play.golang.org.

Run the program given by this link http://play.golang.org/p/PeQ1Cfau8K (note it uses cgo
so it won't run on play). To make it easier to see the below effect you can run `go run`
in a loop, i.e. `while ! go run $GOPATH/src/<package_name>/main.go; do; done`

What happened?

The following intermittent compilation error is printed for a few times then the program
runs successfully:

codez/gocodez/src/github.com/influxdb/testcgo/main.go:20: cannot use o.a (type *C.inner)
as type *C.struct___0 in argument to doSomething

What should have happened instead?

I think the compiler should be consistent and either result in a compilation error or
compile the program successfully. That said, I don't believe the type inner in this case
in incomplete, so the program should compile without any error.

Please provide any additional information below.
@gopherbot

This comment has been minimized.

Copy link
Author

commented Jul 29, 2014

Comment 1 by jvshahid:

I just realized that this should be filed as a compiler bug. Let me know if I should
close this one and reopen it as a compiler bug.
@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Aug 1, 2014

Comment 2:

Labels changed: added repo-main, release-go1.4.

@mdempsky

This comment has been minimized.

Copy link
Member

commented Aug 4, 2014

Comment 3:

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:

  1. _cgo_inner.o (3376 bytes)
  2. _cgo_type_struct___0.o (3376 bytes)
@mdempsky

This comment has been minimized.

Copy link
Member

commented Aug 4, 2014

Comment 4:

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}.
@mdempsky

This comment has been minimized.

Copy link
Member

commented Aug 5, 2014

Comment 5:

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.
@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Aug 5, 2014

Comment 6:

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.

@gopherbot

This comment has been minimized.

Copy link
Author

commented Aug 5, 2014

Comment 7:

CL https://golang.org/cl/122850043 mentions this issue.
@gopherbot

This comment has been minimized.

Copy link
Author

commented Aug 5, 2014

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. :(
@mdempsky

This comment has been minimized.

Copy link
Member

commented Aug 5, 2014

Comment 9:

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.
@mdempsky

This comment has been minimized.

Copy link
Member

commented Aug 5, 2014

Comment 10:

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.
@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Aug 6, 2014

Comment 11:

This issue was closed by revision 0da4b2d.

Status changed to Fixed.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Aug 6, 2014

Comment 12:

Issue #8463 has been merged into this issue.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Aug 6, 2014

Comment 13:

Labels changed: added release-go1.3.1, removed release-go1.4.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Aug 11, 2014

Comment 14:

Issue #8463 has been merged into this issue.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Aug 11, 2014

Comment 15:

Fix is a little more complex than I would like, but it does have a test, and it fixes
intermittent crashes that have no workaround (other than try again). 
Approved for Go 1.3.1.
@adg

This comment has been minimized.

Copy link
Contributor

commented Aug 11, 2014

Comment 16:

This issue was closed by revision 4e9360fa753d.

@adg

This comment has been minimized.

Copy link
Contributor

commented Aug 11, 2014

Comment 17:

Applied to release-branch.go1.3.

@rsc rsc added this to the Go1.3.1 milestone Apr 14, 2015

@rsc rsc removed the release-go1.3.1 label Apr 14, 2015

adg added a commit that referenced this issue May 11, 2015
[release-branch.go1.3] cmd/cgo: fix recursive type mapping
««« 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

@golang golang locked and limited conversation to collaborators Jun 25, 2016

wheatman added a commit to wheatman/go-akaros that referenced this issue Jun 25, 2018
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 golang#8368.
Fixes golang#8441.

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/122850043
wheatman added a commit to wheatman/go-akaros that referenced this issue Jul 9, 2018
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 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.
Projects
None yet
5 participants
You can’t perform that action at this time.