2015-08-10 18:49
浏览 73

如何解决函数调用中更改指针值的问题? 这是CGO的错误吗?

I'm calling a C function via cgo thusly:

var _outptr_7 C.double 
var _outptr_8 C.double  
var kk uintptr = uintptr(unsafe.Pointer(&_outptr_7))
_result := int32(C.gsl_integration_qags((*C.gsl_function)(unsafe.Pointer(f.CPtr())), C.double(a), C.double(b), C.double(epsabs), C.double(epsrel), C.size_t(limit), (*C.gsl_integration_workspace)(unsafe.Pointer(workspace.Ptr())), (*C.double)(&_outptr_7), (*C.double)(&_outptr_8)))
return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))

Now, the kk is here for debugging purposes. I've modified the C function gsl_integration_qags to output the 8th argument it receives (that's &_outptr_7, the _<n> count from 0!)

(The InitializeGslFunction can be ignored for the purpose here...)

The two values - kk and the C function output - match exactly.

However, I get a different number out than the C function returns - it sets the 8th argument via indirection. I'm sure this is correct, I've watched it work in gdb.

It looks like this: (omitting lines that just read (gdb) where I hit enter to repeat command)

Breakpoint 3, qags (f=0xc20800a260, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0x782ec0, result=0xc208031e28, abserr=0xc208031e20, q=0x7ffff79ad12c <gsl_integration_qk21>)
 at qags.c:479
479   *result = res_ext;
(gdb) n
480   *abserr = err_ext;
(gdb) p *result
$1 = -4.0000000000000853
(gdb) p result
$2 = (double *) 0xc208031e28
(gdb) n
482   if (err_ext == GSL_DBL_MAX)
485   if (error_type || error_type2)
513     double max_area = GSL_MAX_DBL (fabs (res_ext), fabs (area)); 
515     if (!positive_integrand && max_area < 0.01 * resabs0)
520     double ratio = res_ext / area;
522     if (ratio < 0.01 || ratio > 100.0 || errsum > fabs (area))
526   goto return_error;
535   if (error_type > 2) 
540   if (error_type == 0) 
542       return GSL_SUCCESS;
573 }
gsl_integration_qags (f=0xc20800a260, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0x782ec0, result=0xc208031e28, abserr=0xc208031e20) at qags.c:53
53    return status ;
54  }

// Correct value (-4.0) is being returned from C function.

_cgo_3ce45c051e63_Cfunc_gsl_integration_qags (v=0xc208031db8) at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:241
asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:669
669     MOVQ    48(SP), DI
670     MOVQ    (g_stack+stack_hi)(DI), SI
671     SUBQ    40(SP), SI
672     MOVQ    DI, g(CX)
673     MOVQ    SI, SP
asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:674
674     RET
runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:627
627     MOVL    AX, ret+16(FP)
runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:628
628     RET
runtime.cgocall_errno (fn=0x405210 <_cgo_3ce45c051e63_Cfunc_gsl_integration_qags>, arg=0xc20805fdb8, ~r2=0) at /usr/lib/golang/src/runtime/cgocall.go:132
132     exitsyscall()
134     return errno

// cgo C glue is about to return from call into Go caller

github.com/dtromb/gogsl/numint._Cfunc_gsl_integration_qags (p0=0xc20800a260, p1=0, p2=1, p3=0, p4=9.9999999999999995e-08, p5=1000, p6=0x782ec0, p7=0xc20805fe28, p8=0xc20805fe20, r1=0)
at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/:92
92  /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/: No such file or directory.

// Bang, it's broken. p7 value in return val struct is /different than the value that went in/... the location of _outptr_7 has changed.

(gdb) p p7
$3 = (github.com/dtromb/gogsl/numint._Ctype_double *) 0xc20805fe28
(gdb) p *p7
$4 = 0
(gdb) n
github.com/dtromb/gogsl/numint.Qags (f=0xc20805ff58, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0xc20800a1d0, ~r7=7753968, ~r8=0, ~r9=0)
at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:75
75     fmt.Printf("%10.10X
76     return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))
(gdb) p _outptr_7
$5 = 0
(gdb) p &_outptr_7
$6 = (float64 *) 0xc20805fe28

// But the correct value is still hanging out there.

 (gdb) p $1
 $7 = -4.0000000000000853

So, what gives? What is going on here? How to fix/workaround?

Here is the cgo binding showing the struct mapping, for completeness:

_cgo_a9ebceabba03_Cfunc_gsl_integration_qags(void *v)
    struct {
            gsl_function* p0;
            double p1;
            double p2;
            double p3;
            double p4;
            size_t p5;
            gsl_integration_workspace* p6;
            double* p7;
            double* p8;
            int r;
            char __pad76[4];
    } __attribute__((__packed__, __gcc_struct__)) *a = v;
    char *stktop = _cgo_topofstack();
    __typeof__(a->r) r = gsl_integration_qags((void*)a->p0, a->p1, a->p2, a->p3, a->p4, a->p5, (void*)a->p6, (void*)a->p7, (void*)a->p8);
    a = (void*)((char*)a + (_cgo_topofstack() - stktop));
    a->r = r;

The bug occurs or does not occur randomly depending on some details of the compilation which should not affect semantics - adding a line which prints out &_outptr_7 before calling the C function causes it to return correctly, for example. Making other changes to the code reverts it back, etc etc.

Something I'm doing wrong? Or bug in cgo?

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dsqdpn31467 2015-10-27 16:43

    This is due to a bug in Go 1.4. Fixed in 1.5.


    解决 无用
    打赏 举报

相关推荐 更多相似问题