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

cmd/cgo: retain Go pointer passed to C call for duration of call

Fixes #6397.

R=golang-dev, bradfitz, iant
CC=golang-dev
https://golang.org/cl/13858043
This commit is contained in:
Russ Cox 2013-09-24 15:52:48 -04:00
parent 7616c94921
commit 5639d2754b
2 changed files with 25 additions and 6 deletions

View File

@ -651,9 +651,10 @@ bcomplex(Node *n, Node *c)
// Updates the bitvector with a set bit for each pointer containing // Updates the bitvector with a set bit for each pointer containing
// value in the type description starting at offset. // value in the type description starting at offset.
static void static void
walktype1(Type *t, int32 offset, Bvec *bv) walktype1(Type *t, int32 offset, Bvec *bv, int param)
{ {
Type *t1; Type *t1;
int32 o;
switch(t->etype) { switch(t->etype) {
case TCHAR: case TCHAR:
@ -672,21 +673,29 @@ walktype1(Type *t, int32 offset, Bvec *bv)
break; break;
case TIND: case TIND:
case TARRAY: // unlike Go, C passes arrays by reference pointer:
// pointer types // pointer types
if((offset + t->offset) % ewidth[TIND] != 0) if((offset + t->offset) % ewidth[TIND] != 0)
yyerror("unaligned pointer"); yyerror("unaligned pointer");
bvset(bv, ((offset + t->offset) / ewidth[TIND])*BitsPerPointer); bvset(bv, ((offset + t->offset) / ewidth[TIND])*BitsPerPointer);
break; break;
case TARRAY:
if(param) // unlike Go, C passes arrays by reference
goto pointer;
// array in struct or union is an actual array
for(o = 0; o < t->width; o += t->link->width)
walktype1(t->link, offset+o, bv, 0);
break;
case TSTRUCT: case TSTRUCT:
// build map recursively // build map recursively
for(t1 = t->link; t1 != T; t1 = t1->down) for(t1 = t->link; t1 != T; t1 = t1->down)
walktype1(t1, offset, bv); walktype1(t1, offset, bv, 0);
break; break;
case TUNION: case TUNION:
walktype1(t->link, offset, bv); walktype1(t->link, offset, bv, 0);
break; break;
default: default:
@ -728,7 +737,7 @@ dumpgcargs(Type *fn, Sym *sym)
if(t->etype == TVOID) if(t->etype == TVOID)
continue; continue;
argoffset = align(argoffset, t, Aarg1, nil); argoffset = align(argoffset, t, Aarg1, nil);
walktype1(t, argoffset, bv); walktype1(t, argoffset, bv, 1);
argoffset = align(argoffset, t, Aarg2, nil); argoffset = align(argoffset, t, Aarg2, nil);
} }
gextern(sym, nodconst(bv->n), 0, 4); gextern(sym, nodconst(bv->n), 0, 4);

View File

@ -413,7 +413,17 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
if argSize == 0 { if argSize == 0 {
argSize++ argSize++
} }
fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize) // TODO(rsc): The struct here should declare pointers only where
// there are pointers in the actual argument frame.
// This is a workaround for golang.org/issue/6397.
fmt.Fprintf(fc, "·%s(struct{", n.Mangle)
if n := argSize / p.PtrSize; n > 0 {
fmt.Fprintf(fc, "void *y[%d];", n)
}
if n := argSize % p.PtrSize; n > 0 {
fmt.Fprintf(fc, "uint8 x[%d];", n)
}
fmt.Fprintf(fc, "}p)\n")
fmt.Fprintf(fc, "{\n") fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
if n.AddError { if n.AddError {