[ErrorCatch] runtime error: cgo argument has Go pointer to Go pointer

Hi,

I want to pass a GO pointer through C back to a GO callback… and get the error from above. If I disable the cgo checker with:

export GODEBUG=cgocheck=0

everything works fine;

Details: i want to pass the argv variable []interface{} through C back to GO

// PROBLEM: [ErrorCatch] runtime error: cgo argument has Go pointer to Go pointer
// SOLVE:   export GODEBUG=cgocheck=0
func (this *MqC) Send (callSig string, argv ...interface{}) {
  hdl := this.getCTX()
  callSig_ptr := (C.MQ_CST)(C.CString(callSig))
  defer C.free((unsafe.Pointer)(callSig_ptr))

  var errVal C.enum_MqErrorE = C.gomsgque_Send(hdl, callSig_ptr, C.MQ_INT(len(argv)), unsafe.Pointer(&argv))

  if (errVal > C.MQ_CONTINUE) { MqErrorC_Check(C.MQ_MNG(hdl), errVal) }
}

The callback is

//export atomSet
func atomSet( hdl   C.MQ_MNG, objv  unsafe.Pointer, skip  C.MQ_INT, typ C.enum_MqSendE,
                inP  unsafe.Pointer) C.enum_MqErrorE {
  ifc := (*(*[]interface{})(objv))[skip]
...
}

now I would like to have a GO friendly solution.
thanks.

I don’t know how Go’s internals work, but here’s a guess:

Based on the deferred free of the callSig_ptr string pointer, it looks to me like both callSig and argv are not supposed to live after the call to (*MqC).Send, but the Go compiler doesn’t know that. It just sees that you’re passing the address of a local parameter (argv) into C and that value might be supposed to live past the call to gomsgque_Send.

If gomsgque_Send stored a reference to &argv somewhere in the "C world," then (*MqC).Send returned, then a garbage collection ran (cleaning up the argv that escaped to the heap in the call to (*MqC).Send), when atomSet is eventually called, it would crash with a segmentation fault because argv was cleaned up.

If the lifetimes of callSig and argv don’t need to survive after gomsgque_Send returns, try getting the address outside of the call to gomsgque_Send to something like this:

func (this *MqC) Send (callSig string, argv ...interface{}) {
  hdl := this.getCTX()
  callSig_ptr := (C.MQ_CST)(C.CString(callSig))
  defer C.free((unsafe.Pointer)(callSig_ptr))

  argv_ptr := unsafe.Pointer(&argv)

  var errVal C.enum_MqErrorE = C.gomsgque_Send(hdl, callSig_ptr, C.MQ_INT(len(argv)), argv_ptr)

  if (errVal > C.MQ_CONTINUE) { MqErrorC_Check(C.MQ_MNG(hdl), errVal) }
}

I’m not positive that will work, but try it out.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.