如何解决函数调用中指针值的变化?这是一个cgo的错误吗?

huangapple go评论119阅读模式
英文:

How to resolve changing pointer value in function call? Is this a cgo bug?

问题

我正在通过cgo调用一个C函数,代码如下:

  1. var _outptr_7 C.double
  2. var _outptr_8 C.double
  3. var kk uintptr = uintptr(unsafe.Pointer(&_outptr_7))
  4. gogsl.InitializeGslFunction(f)
  5. _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)))
  6. fmt.Printf("%10.10X\n",kk)
  7. return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))

现在,kk是用于调试目的的。我修改了C函数gsl_integration_qags,使其输出它接收到的第8个参数(即&_outptr_7,从0开始计数的_n!)

(这里可以忽略InitializeGslFunction函数...)

kk和C函数的输出结果完全一致。

然而,我得到的结果与C函数返回的结果不同 - 它通过间接方式设置第8个参数。我确信这是正确的,我在gdb中观察过它的工作。

具体情况如下:(省略了只读取(gdb)的行,我按回车键重复命令)

  1. 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>)
  2. at qags.c:479
  3. 479 *result = res_ext;
  4. (gdb) n
  5. 480 *abserr = err_ext;
  6. (gdb) p *result
  7. $1 = -4.0000000000000853
  8. (gdb) p result
  9. $2 = (double *) 0xc208031e28
  10. (gdb) n
  11. 482 if (err_ext == GSL_DBL_MAX)
  12. 485 if (error_type || error_type2)
  13. 513 double max_area = GSL_MAX_DBL (fabs (res_ext), fabs (area));
  14. 515 if (!positive_integrand && max_area < 0.01 * resabs0)
  15. 520 double ratio = res_ext / area;
  16. 522 if (ratio < 0.01 || ratio > 100.0 || errsum > fabs (area))
  17. 526 goto return_error;
  18. 535 if (error_type > 2)
  19. 540 if (error_type == 0)
  20. 542 return GSL_SUCCESS;
  21. 573 }
  22. 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
  23. 53 return status ;
  24. 54 }
  25. // 正确的值(-4.0)从C函数返回。
  26. _cgo_3ce45c051e63_Cfunc_gsl_integration_qags (v=0xc208031db8) at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:241
  27. asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:669
  28. 669 MOVQ 48(SP), DI
  29. 670 MOVQ (g_stack+stack_hi)(DI), SI
  30. 671 SUBQ 40(SP), SI
  31. 672 MOVQ DI, g(CX)
  32. 673 MOVQ SI, SP
  33. asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:674
  34. 674 RET
  35. runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:627
  36. 627 MOVL AX, ret+16(FP)
  37. runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:628
  38. 628 RET
  39. runtime.cgocall_errno (fn=0x405210 <_cgo_3ce45c051e63_Cfunc_gsl_integration_qags>, arg=0xc20805fdb8, ~r2=0) at /usr/lib/golang/src/runtime/cgocall.go:132
  40. 132 exitsyscall()
  41. 134 return errno
  42. // cgo C绑定即将从Go调用者返回
  43. 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)
  44. at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/:92
  45. 92 /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/: No such file or directory.
  46. // 糟糕,出错了。返回值结构体中的p7值与输入值不同... **_outptr_7的位置已经改变**。
  47. (gdb) p p7
  48. $3 = (github.com/dtromb/gogsl/numint._Ctype_double *) 0xc20805fe28
  49. (gdb) p *p7
  50. $4 = 0
  51. (gdb) n
  52. 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)
  53. at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:75
  54. 75 fmt.Printf("%10.10X\n",kk)
  55. C208031E28
  56. 76 return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))
  57. (gdb) p _outptr_7
  58. $5 = 0
  59. (gdb) p &_outptr_7
  60. $6 = (float64 *) 0xc20805fe28
  61. // 但是正确的值仍然存在。
  62. (gdb) p $1
  63. $7 = -4.0000000000000853
  64. 那么,出了什么问题?这里发生了什么?如何修复/解决?
  65. 为了完整起见,这是cgo绑定显示的结构体映射:
  66. ```c
  67. void
  68. _cgo_a9ebceabba03_Cfunc_gsl_integration_qags(void *v)
  69. {
  70. struct {
  71. gsl_function* p0;
  72. double p1;
  73. double p2;
  74. double p3;
  75. double p4;
  76. size_t p5;
  77. gsl_integration_workspace* p6;
  78. double* p7;
  79. double* p8;
  80. int r;
  81. char __pad76[4];
  82. } __attribute__((__packed__, __gcc_struct__)) *a = v;
  83. char *stktop = _cgo_topofstack();
  84. __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);
  85. a = (void*)((char*)a + (_cgo_topofstack() - stktop));
  86. a->r = r;
  87. }

这个错误在编译的某些细节上是随机发生或不发生的,这些细节不应该影响语义 - 例如,在调用C函数之前添加一个打印&_outptr_7的行会导致它正确返回。对代码进行其他更改会使其恢复,等等。

我做错了什么吗?还是cgo的一个错误?

英文:

I'm calling a C function via cgo thusly:

  1. var _outptr_7 C.double
  2. var _outptr_8 C.double
  3. var kk uintptr = uintptr(unsafe.Pointer(&amp;_outptr_7))
  4. gogsl.InitializeGslFunction(f)
  5. _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)(&amp;_outptr_7), (*C.double)(&amp;_outptr_8)))
  6. fmt.Printf(&quot;%10.10X\n&quot;,kk)
  7. return _result, *(*float64)(unsafe.Pointer(&amp;_outptr_7)), *(*float64)(unsafe.Pointer(&amp;_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 &amp;_outptr_7, the _&lt;n&gt; 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)

  1. 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 &lt;gsl_integration_qk21&gt;)
  2. at qags.c:479
  3. 479 *result = res_ext;
  4. (gdb) n
  5. 480 *abserr = err_ext;
  6. (gdb) p *result
  7. $1 = -4.0000000000000853
  8. (gdb) p result
  9. $2 = (double *) 0xc208031e28
  10. (gdb) n
  11. 482 if (err_ext == GSL_DBL_MAX)
  12. 485 if (error_type || error_type2)
  13. 513 double max_area = GSL_MAX_DBL (fabs (res_ext), fabs (area));
  14. 515 if (!positive_integrand &amp;&amp; max_area &lt; 0.01 * resabs0)
  15. 520 double ratio = res_ext / area;
  16. 522 if (ratio &lt; 0.01 || ratio &gt; 100.0 || errsum &gt; fabs (area))
  17. 526 goto return_error;
  18. 535 if (error_type &gt; 2)
  19. 540 if (error_type == 0)
  20. 542 return GSL_SUCCESS;
  21. 573 }
  22. 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
  23. 53 return status ;
  24. 54 }

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

  1. _cgo_3ce45c051e63_Cfunc_gsl_integration_qags (v=0xc208031db8) at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:241
  2. asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:669
  3. 669 MOVQ 48(SP), DI
  4. 670 MOVQ (g_stack+stack_hi)(DI), SI
  5. 671 SUBQ 40(SP), SI
  6. 672 MOVQ DI, g(CX)
  7. 673 MOVQ SI, SP
  8. asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:674
  9. 674 RET
  10. runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:627
  11. 627 MOVL AX, ret+16(FP)
  12. runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:628
  13. 628 RET
  14. runtime.cgocall_errno (fn=0x405210 &lt;_cgo_3ce45c051e63_Cfunc_gsl_integration_qags&gt;, arg=0xc20805fdb8, ~r2=0) at /usr/lib/golang/src/runtime/cgocall.go:132
  15. 132 exitsyscall()
  16. 134 return errno

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

  1. 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)
  2. at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/:92
  3. 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.

  1. (gdb) p p7
  2. $3 = (github.com/dtromb/gogsl/numint._Ctype_double *) 0xc20805fe28
  3. (gdb) p *p7
  4. $4 = 0
  5. (gdb) n
  6. 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)
  7. at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:75
  8. 75 fmt.Printf(&quot;%10.10X\n&quot;,kk)
  9. C208031E28
  10. 76 return _result, *(*float64)(unsafe.Pointer(&amp;_outptr_7)), *(*float64)(unsafe.Pointer(&amp;_outptr_8))
  11. (gdb) p _outptr_7
  12. $5 = 0
  13. (gdb) p &amp;_outptr_7
  14. $6 = (float64 *) 0xc20805fe28

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

  1. (gdb) p $1
  2. $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:

  1. void
  2. _cgo_a9ebceabba03_Cfunc_gsl_integration_qags(void *v)
  3. {
  4. struct {
  5. gsl_function* p0;
  6. double p1;
  7. double p2;
  8. double p3;
  9. double p4;
  10. size_t p5;
  11. gsl_integration_workspace* p6;
  12. double* p7;
  13. double* p8;
  14. int r;
  15. char __pad76[4];
  16. } __attribute__((__packed__, __gcc_struct__)) *a = v;
  17. char *stktop = _cgo_topofstack();
  18. __typeof__(a-&gt;r) r = gsl_integration_qags((void*)a-&gt;p0, a-&gt;p1, a-&gt;p2, a-&gt;p3, a-&gt;p4, a-&gt;p5, (void*)a-&gt;p6, (void*)a-&gt;p7, (void*)a-&gt;p8);
  19. a = (void*)((char*)a + (_cgo_topofstack() - stktop));
  20. a-&gt;r = r;
  21. }

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

得分: 0

这是由于Go 1.4中的一个错误导致的。在1.5中已经修复。

https://golang.org/issue/10303

英文:

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

https://golang.org/issue/10303

huangapple
  • 本文由 发表于 2015年8月11日 02:49:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/31926976.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定