how to copy C.int address into C.char in cgo? - c

using cgo I am calling c function. I ran into situation where I have to copy C.int address into C.char[4]. Can I do that in go?
code snippet C- Structure:
struct data
{
char *a_add;
unsigned int length;
}
Go-Code
func main() {
var d[3] C.data
var filedescriptor C.int
d[0].a_add = &filedescriptor
d[0].length = 4
}
The problem is a_add is a char*. But I need to pass int variable address. The c-code is a legacy code, and I can't fix datatype now. Other C modules uses it, and it's working in C with a warning. where as in go, it is error.
Is there any way that I can copy address of int variable into char* array in cgo.
Update:
I tried d[0].a_add = (*C.char)(unsafe.Pointer(&filedescriptor )),
getting Error:
panic: runtime error: cgo argument has Go pointer to Go pointer
What Am I missing?

One of the problems you are running into is that in a call into C code, you may not pass a pointer to a Go pointer. The variable filedescriptor is a C.int, but &filedescriptor is a Go pointer, so you cannot use that (or rather, you cannot use that in the a_add field as a value).
There is a great deal about your C code that is not clear to me, but you can probably use the code below. Note that this code may be overkill for your particular situation. It is not meant to be particularly efficient or good, just as clear as possible while being extremely flexible—for instance, it can read from and write to packed C structures.
package main
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
//
// struct data {
// char *a_add;
// unsigned int length;
// };
//
// void f(struct data *p) {
// printf("p->a_add = %p, p->length = %u\n", p->a_add, p->length);
// printf("p->a_add as an int: %d\n", *(int *)p->a_add);
// *(int *)p->a_add = 0x12345678;
// }
import "C"
import (
"fmt"
"unsafe"
)
const cIntSize = C.sizeof_int
// Produce a Go int64 from a C int. The caller passes the address
// of the C int.
func int64FromCInt(ci unsafe.Pointer) int64 {
// Get a slice pointing to the bytes of the C int.
sci := (*[cIntSize]byte)(ci)[:]
switch {
case cIntSize == unsafe.Sizeof(int64(0)):
var gi int64
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sgi, sci)
return gi
case cIntSize == unsafe.Sizeof(int32(0)):
var gi int32
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sgi, sci)
return int64(gi)
case cIntSize == unsafe.Sizeof(int(0)):
var gi int
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sgi, sci)
return int64(gi)
default:
panic("no Go integer size matches C integer size")
}
}
// Write C int (via an unsafe.Pointer) from Go int. The caller
// passes the address of the C int.
func writeCIntFromInt(gi int, ci unsafe.Pointer) {
// Get a slices covering the bytes of the C int.
sci := (*[cIntSize]byte)(ci)[:]
switch {
case cIntSize == unsafe.Sizeof(gi):
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sci, sgi)
case cIntSize == unsafe.Sizeof(int64(0)):
// Copy value to int64 for copying purposes.
// Since int64 holds all int values, this always works.
gi2 := int64(gi)
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi2))[:]
copy(sci, sgi)
case cIntSize == unsafe.Sizeof(int32(0)):
// Copy value to int32 for copying purposes.
// Panic if we destroy the value via truncation.
gi2 := int32(gi)
if int(gi2) != gi {
panic(fmt.Sprintf("unable to send Go value %x to C: size of Go int=%d, size of C int=%d", gi, unsafe.Sizeof(gi), cIntSize))
}
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi2))[:]
copy(sci, sgi)
default:
panic("no Go integer size matches C integer size")
}
}
func main() {
b := C.malloc(cIntSize)
defer C.free(b)
writeCIntFromInt(32767, b)
d := C.struct_data{a_add: (*C.char)(b), length: cIntSize}
fmt.Println("calling C.f(d)")
C.f(&d)
result := int64FromCInt(unsafe.Pointer(d.a_add))
fmt.Printf("result = %#x\n", result)
}

Related

LLVM IR -- how to convert array store to memcpy?

LLVM IR includes arrays as a base type, so a "store" instruction in IR will take an array object and store it to a pointer to memory.
I'm compiling to a C environment, so I need to convert "store" instructions to calls to memcpy. I've tried to use IRBuilder to make the job easier, but I'm stuck on how to take the address of an object.
The function I've written is as follows:
bool convert_array_store_to_memcpy(llvm::StoreInst *instruction)
{
llvm::Type *value_type = instruction->getValueOperand()->getType();
if (!value_type->isArrayTy())
return false;
/* set up IRBuilder and get the pieces of the store */
llvm::IRBuilder<> Builder(llvm::getGlobalContext());
Builder.SetInsertPoint(instruction);
llvm::Value *destination = instruction->getPointerOperand();
llvm::Value *source = instruction->getValueOperand();
/* get the number of bytes by getting the size of the array (elements*element-size) */
llvm::ArrayType *array_type = cast<ArrayType>(value_type);
uint64_t element_count = array_type->getNumElements();
llvm::Type *element_type = array_type->getElementType();
DataLayout *targetData = new DataLayout(mod);
uint64_t element_size = targetData->getTypeAllocSize(element_type);
uint64_t size = element_count*element_size;
/* PROBLEM: I am trying to take the address of the start of the array */
llvm::Type *i32_type = llvm::IntegerType::getInt32Ty(llvm::getGlobalContext());
llvm::Constant *constant_int = llvm::ConstantInt::get(i32_type, 0, true);
Value *indexList[1] = {constant_int};
/* NEW PROBLEM:indexList seems to be the wrong type or contain the wrong type of thing */
llvm::Value *pointer_to_source = Builder.CreateGEP(source, ArrayRef<Value*>(indexList, 1));
unsigned alignment = instruction->getAlignment();
if (!array_type)
fprintf(stderr, "ERROR!\n");
/* insert the memcpy */
llvm::CallInst *memcpy_call = Builder.CreateMemCpy(destination,
pointer_to_source,
size,
alignment,
instruction->isVolatile());
/* erase the store */
instruction->eraseFromParent();
return true;
} /* convert_array_store_to_memcpy */
This compiles, but I get the following runtime error from the call to IRBuilder::CreateGEP:
.../llvm/install/include/llvm/IR/Instructions.h:782: llvm::Type
*llvm::checkGEPType(llvm::Type *): Assertion `Ty && "Invalid GetElementPtrInst indices for type!"' failed.
Note that I'm using LLVM 3.6 under Linux.
EDIT: clearly, the call to createGEP is sending a null instead of the constant zero -- the intent was to get the address of the zeroth element of the array. I've edited the above function with my latest effort, which is to try to send a length-1 array of indices into createGEP. This is also failing inside of getIndexedType, which returns a NULL pointer, which I, again, don't understand.
Note: I am using the example from a previous StackOverflow answer: Inserting GetElementpointer Instruction in LLVM IR

Pointer from C is removed from memory

In this situation, I pass a pointer from Go to a C function, the C function modifies that pointer value (fills in an array) and I use the same pointer again on the Go code, making sure to call C.free to release it after I am done.
I am sometimes getting a nil reference on that pointer, I am having a hard time understanding why.
Here, the object in Go is cpuTimesC, in C it is the cputicks.
I have also tried making the function return the pointer, with the same results. The weirdest thing is that if I put a printf statement at the end of the function, it takes longer before I eventually get the nil error.
package collector
/*
#cgo LDFLAGS: -lperfstat
#include <stdlib.h>
#include <stdio.h>
#include <libperfstat.h>
#include <string.h>
#include <time.h>
u_longlong_t **ref;
int getCPUTicks(uint64_t **cputicks, size_t *cpu_ticks_len) {
int i, ncpus, cputotal;
perfstat_id_t firstcpu;
perfstat_cpu_t *statp;
cputotal = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
if (cputotal <= 0){
return -1;
}
statp = calloc(cputotal, sizeof(perfstat_cpu_t));
if(statp==NULL){
return -1;
}
ncpus = perfstat_cpu(&firstcpu, statp, sizeof(perfstat_cpu_t), cputotal);
*cpu_ticks_len = ncpus*4;
*cputicks = (uint64_t *) malloc(sizeof(uint64_t)*(*cpu_ticks_len));
for (i = 0; i < ncpus; i++) {
int offset = 4 * i;
(*cputicks)[offset] = statp[i].user;
(*cputicks)[offset+1] = statp[i].sys;
(*cputicks)[offset+2] = statp[i].wait;
(*cputicks)[offset+3] = statp[i].idle;
}
return 0;
}
*/
import "C"
import (
"errors"
"unsafe"
"fmt"
"github.com/prometheus/client_golang/prometheus"
)
const ClocksPerSec = float64(C.CLK_TCK)
const maxCPUTimesLen = 1024 * 4
type statCollector struct {
cpu *prometheus.Desc
}
func init() {
registerCollector("cpu", true, NewCPUCollector)
}
func NewCPUCollector() (Collector, error) {
return &statCollector{
cpu: nodeCPUSecondsDesc,
}, nil
}
func (c *statCollector) Update(ch chan<- prometheus.Metric) error {
var fieldsCount = 4
cpuFields := []string{"user", "sys", "wait", "idle"}
var (
cpuTimesC *C.uint64_t
cpuTimesLength C.size_t
)
if C.getCPUTicks(&cpuTimesC, &cpuTimesLength) == -1 {
return errors.New("could not retrieve CPU times")
}
defer C.free(unsafe.Pointer(cpuTimesC))
cput := (*[maxCPUTimesLen]C.u_longlong_t)(unsafe.Pointer(cpuTimesC))[:cpuTimesLength:cpuTimesLength]
cpuTicks := make([]float64, cpuTimesLength)
for i, value := range cput {
cpuTicks[i] = float64(value) / ClocksPerSec
}
for i, value := range cpuTicks {
cpux := fmt.Sprintf("CPU %d", i/fieldsCount)
ch <- prometheus.MustNewConstMetric(c.cpu, prometheus.CounterValue, value, cpux, cpuFields[i%fieldsCount])
}
return nil
}
The error is:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x33 addr=0x0 pc=0x1003fcec0]
goroutine 940 [running]:
github.com/dlopes7/aix-prometheus-exporter/collector.(*statCollector).Update(0xa000100000d21b8, 0xa0001000028c480, 0x0, 0x0)
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/cpu_aix.go:81 +0xf0
github.com/dlopes7/aix-prometheus-exporter/collector.execute(0x10043e7e7, 0x3, 0x1101120e0, 0xa000100000d21b8, 0xa0001000028c480)
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/collector.go:95 +0x6c
github.com/dlopes7/aix-prometheus-exporter/collector.AIXCollector.Collect.func1(0xa0001000028c480, 0xa000100000cd440, 0x10043e7e7, 0x3, 0x1101120e0, 0xa000100000d21b8)
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/collector.go:115 +0x4c
created by github.com/dlopes7/aix-prometheus-exporter/collector.AIXCollector.Collect
/home/david/go/src/github.com/dlopes7/aix-prometheus-exporter/collector/collector.go:114 +0xf8
And I know it happens here, because for some reason cpuTimesC is nil:
cput := (*[maxCPUTimesLen]C.u_longlong_t)(unsafe.Pointer(cpuTimesC))[:cpuTimesLength:cpuTimesLength]
Why would this object be nil sometimes, and how do I make it remain in memory until I call that C.free?
This is on AIX PPC64 with cgo if that makes any difference.
This had nothing to do with pointers being removed from memory, the cputicks was NULL because ncpus was -1 so the malloc call returned NULL, ncpu was -1 because the first parameter of the perfstat_cpu call was not initialized properly, adding:
strcpy(firstcpu.name, FIRST_CPU);
Before the call to perfstat_cpu fixed the issue, as suggested by #kostik

C call Go exported function

I want to return an array to C caller, just like below, how to do it?
//export EtcdGetAllNodes
func EtcdGetAllNodes()[]uint32 {
a := []uint32{1,2,3}
return a
}
This function EtcdGetAllNodes will try to get value with a prefix for the specific key from etcd, it will return multiple values. How to return these values to C caller?
Command cgo
Passing pointers
A Go function called by C code may not return a Go pointer (which
implies that it may not return a string, slice, channel, and so
forth). A Go function called by C code may take C pointers as
arguments, and it may store non-pointer or C pointer data through
those pointers, but it may not store a Go pointer in memory pointed to
by a C pointer. A Go function called by C code may take a Go pointer
as an argument, but it must preserve the property that the Go memory
to which it points does not contain any Go pointers.
I want to return an array to C caller.
//export EtcdGetAllNodes
func EtcdGetAllNodes() []uint32 {
a := []uint32{1, 2, 3}
return a
}
A Go function called by C code may not return a Go pointer (which implies that it may not return a slice).
There are many possible solutions: Command cgo.
For example, here is one simple solution:
Output:
$ go build -buildmode=c-archive -o cmem.a cmem.go
$ gcc -pthread -o cmem cmem.c cmem.a
$ ./cmem
-- EtcdGetAllNodes --
nodes: 3
node 0: 1
node 1: 2
node 2: 3
$ echo $?
0
$
cmem.go:
package main
/*
#include <stdint.h>
#include <stdlib.h>
*/
import "C"
import "unsafe"
// toC: Go slice to C array
// c[0] is the number of elements,
// c[1] through c[c[0]] are the elements.
// When no longer in use, free the C array.
func toC(a []uint32) *C.uint32_t {
// C array
ca := (*C.uint32_t)(C.calloc(C.size_t(1+len(a)), C.sizeof_uint32_t))
// Go slice of C array
ga := (*[1 << 30]uint32)(unsafe.Pointer(ca))[: 1+len(a) : 1+len(a)]
// number of elements
ga[0] = uint32(len(a))
// elements
for i, e := range a {
ga[1+i] = e
}
return ca
}
//export EtcdGetAllNodes
// EtcdGetAllNodes: return all nodes as a C array.
// nodes[0] is the number of node elements.
// nodes[1] through nodes[nodes[0]] are the node elements.
// When no longer in use, free the nodes array.
func EtcdGetAllNodes() *C.uint32_t {
// TODO: code to get all etcd nodes
a := []uint32{1, 2, 3}
// nodes as a C array
return toC(a)
}
func main() {}
cmem.c:
#include "cmem.h"
#include <stdint.h>
#include <stdio.h>
int main() {
printf("-- EtcdGetAllNodes --\n");
// nodes[0] is the number of node elements.
// nodes[1] through nodes[nodes[0]] are the node elements.
// When no longer in use, free the nodes array.
uint32_t *nodes = EtcdGetAllNodes();
if (!nodes) {
return 1;
}
printf("nodes: %d\n", *nodes);
for (uint32_t i = 1; i <= *nodes; i++) {
printf("node %d: %d\n", i-1,*(nodes+i));
}
free(nodes);
return 0;
}

Pass double array by reference from C to Delphi DLL

For our Delphi (XE5) application we are developing an API. In order to communicate data from the Delphi DLL functions with the main program (C based; either (console) C or C++ code applications or Matlab and Simulink) arrays that are allocated by the caller need to be filled with doubles by the DLL.
I understand that open array (Delphi specific) are not very convenient for this purpose as they contain additional data that you then have to mimic in C. Instead I was planning to use pointer arithmetic (see dll function: inc(APDouble)) by directly pointing to the correct address. My question is if this is how you software developers would do this.
A demo is included below (full sources).
The DLL (made in DXE5):
library PDA;
uses
System.StrUtils,
System.SysUtils,
Vcl.Dialogs;
{$R *.res}
function ShowArrayContents( APDouble: PDouble;
size: Integer): integer; cdecl; export;
var
i: Integer;
begin
Result := 0;
for i := 0 to size-1 do
begin
// Show value!
MessageDlg(Format('%p -> %p -> %f', [#APDouble, APDouble, APDouble^]), mtWarning, [mbOK], 0);
Inc(APDouble);
end;
end;
exports
ShowArrayContents;
begin
end.
The C-code caller (made in C++ builder XE4):
#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include <windows.h>
typedef int (*_ShowArrayContents) (double *, int);
char *dllname = "PDA.dll";
static HINSTANCE hInstanceControl;
_ShowArrayContents ShowArrayContents = NULL;
int _tmain(int argc, _TCHAR* argv[])
{
double DVals[3] = {1.23, 4.56, 7.89};
int i;
hInstanceControl = LoadLibrary(dllname);
if( hInstanceControl != NULL){
ShowArrayContents =(_ShowArrayContents)GetProcAddress(hInstanceControl, "ShowArrayContents");
} else {
return 0;
}
// test program:
(*ShowArrayContents)(&DVals[0], 3);
FreeLibrary(hInstanceControl);
system("pause");
return 0;
}
Your code works fine, but as you observe it is awkward. For interop like this I would bite the bullet and use the $POINTERMATH directive. This allows you to treat a pointer as if it were an array, just as you do in C or C++. For example:
{$POINTERMATH ON}
function GetSum(arr: PDouble; len: Integer): Double; cdecl;
var
i: Integer;
begin
Result := 0.0;
for i := 0 to len-1 do
Result := Result + arr[i];
end;
Another option would be to copy to a native Delphi array and use that for onward processing. Obviously that involves a copy, but sometimes that's actually what you want. In that case you could do it like this:
var
x: TArray<Double>;
....
SetLength(x, len);
Move(arr^, Pointer(x)^, len*SizeOf(arr^));
Or if you don't like the use of Move, a good old loop:
{$POINTERMATH ON}
var
i: Integer;
x: TArray<Double>;
....
SetLength(x, len);
for i := 0 to len-1 do
x[i] := arr[i];

When is CAMLparamX required?

I am writing an interface to a C-library using external declarations in OCaml. I used ctypes for testing but it involved a 100% overhead for fast calls (measured by a core_bench micro benchmark).
The functions look like this:
/* external _create_var : float -> int -> int -> int -> _npnum = "ocaml_tnp_number_create_var" ;; */
value ocaml_tnp_number_create_var(value v, value nr, value p, value o) {
//CAMLparam4(v, nr, p, o);
const int params = Int_val(p);
const int order = Int_val(o);
const int number = Int_val(nr);
const double value = Double_val(v);
return CTYPES_FROM_PTR(tnp_number_create_variable(value, number, params, order));
}
/* external _delete : _npnum -> unit = "ocaml_tnp_number_delete" ;; */
value ocaml_tnp_number_delete(value num) {
//CAMLparam1(num);
struct tnp_number* n = CTYPES_TO_PTR(num);
tnp_number_delete(n);
return Val_unit;
}
I borrowed the CTYPES_* macros, so I am basically moving pointers around as Int64 values.
#define CTYPES_FROM_PTR(P) caml_copy_int64((intptr_t)P)
#define CTYPES_TO_PTR(I64) ((void *)Int64_val(I64))
#define CTYPES_PTR_PLUS(I64, I) caml_copy_int64(Int64_val(I64) + I)
AFAIK, those values are represented as boxes which are tagged as "custom", which should be left untouched by the GC.
Do I need to uncomment the CAMLparamX macros to notify the GC about my usage or is it legal to omit them?
According to the comment in byterun/memory.h your function must start with a CAMLparamN macro with all value parameters.

Resources