I have a type stored in C, that's a pointer to a type.
type
MyType = object
var point = cast[ptr MyType](someCAllocFunction(sizeof(ptr MyType)))
GC_ref(point) # this doesn't work, because GC_ref expects a ``ref T``, ``seq[T]``, or ``string``
How can I achieve this?
I need to pass around some data between Nim and C, and this someCAllocFunction returns a void pointer. I tried casting it to a ptr MyType and setting its value using point[] = MyType() (in reality I'm using an object with some fields, and the object is initialized in a separate function). But then, in a callback I passed to C, I'm trying to access my data again, but a SIGSEGV is raised.
instance of TestAutowrenType
Traceback (most recent call last)
autowren.nim(143) autowren
autowren.nim(136) w_data=
autowren.nim(130) data=
gc.nim(289) unsureAsgnRef
gc.nim(185) decRef
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Here's the source code of my program: https://github.com/liquid600pgm/rapid/blob/master/src/scripting/autowren.nim
I understood this as the GC removing my object while it's passed around in C code, and that's why I wanted to mark it as referenced.
The way you asked your question (hint: vague, general, not clear what you really want) Araq responded perfectly correctly.
Now you ask us to read a 150 lines file and we are supposed to find out what you want and what your problem is by reading through and make sense of your code.. Chances for that to happen are slim I guess.
Maybe helpful: Sometimes C stuff wants/needs some structs and stuff allocated by a caller. In such cases it's often better to do those allocations in C and to pass them to Nim in a way where the Nim code doesn't need to know anything about them (other than that they are pointers of some kind). As long as the Nim code doesn't need to do anything with those pointers (other than passing them around) you need not be precise; you can, for instance, tell Nim that some pointer to some <complicated C structure> is simply a char pointer.
Another maybe helpful hint is to "allocate" simple stuff (like say a C char array) in Nim (by simply having a var) and to pass the pointer to it (more precisely usually a pointer to its data) via myvar.addr() to a C function. Do not allocate a bit here (Nim) and bit there (C) but try to be consistent.
For a more specific answer you need to provide a more specific problem description.
Well, maybe instead of asking you to solve my problem let me ask a more general question about pointers: From what I understand, ptr T is untracked by the GC. So can I just do something like this?
type
MyObj = object
x: int
proc newMyObj(): MyObj =
result = MyObj(x: 42)
proc allocMyObj(): ptr MyObj =
result = cast[ptr MyObj](alloc(sizeof(ptr MyObj)))
result[] = newMyObj()
Or will this cause some sort of memory problems?
I'm asking this question because I'm not very experienced with such low-level programming, and my application uses pretty much what I've shown in the example (except alloc() isn't used directly, but it more or less resembles what I'm doing in my code)
alloc(sizeof(ptr MyObj))
seems to be a typo. Guess it should be alloc(sizeof(MyObj))
Yes and no.
Yes insofar as you can of course allocate whatever you please and pass those pointers around and/or use them. No insofar as you must be careful to not wildly mix up Nim-allocated objects and pointers. In your example
proc newMyObj(): MyObj =
result = MyObj(x: 42)
proc allocMyObj(): ptr MyObj =
result = cast[ptr MyObj](alloc(sizeof(ptr MyObj)))
result[] = newMyObj()
there are multiple problems. For one result[] = newMyObj() says "return what result points to" which however is not a pointer. More gravely though, even if it worked you would lose the just allocated pointer/memory because you would overwrite result with what MyObj() returns.
What you actually wanted is probably this:
proc allocMyObj(): ptr MyObj =
result = cast[ptr MyObj](alloc(sizeof(MyObj)))
result[].x = 42
Alternatively you could also use your newMyObj() proc instead of allocMyObj() but then your object were a Nim (allocated) object and taking its address to have a pointer to pass around (to C code) would risk to end in a weird situation because from Nims point of view it is in charge of that object while from C's point of view it could do with that pointer whatever it pleases and assume its - not guaranteed - existence etc.
Maybe the following code can help you to see what I mean
type
MyObj = object
x: int
proc newMyObj(v: int): MyObj =
result = MyObj(x: v)
proc allocMyObj(): ptr MyObj =
result = cast[ptr MyObj](alloc(sizeof(MyObj)))
var tmp = newMyObj(42) # under the hood a Nim ref
echo "tmp: " & tmp.repr() & "tmp address: " & repr(tmp.addr()) # show it from Nim's point of view
echo "allocated object: " & result.repr() # now show the alloc'd object
result = tmp.addr() # but return the other one bc. result has been overwritten
# -- main --
let mo = allocMyObj()
# the allocated object is lost. We have no way to access or free it
echo "After allocMyObj(): " & mo.repr()
mo.dealloc() # deallocates which one? Obviously *not* the alloc'd one
let mo2 = newMyObj(43) # try it the other way
echo "After newMyObj(): " & mo2.repr()
there are multiple problems. For one result[] = newMyObj() says "return what result points to" which however is not a pointer. More gravely though, even if it worked you would lose the just allocated pointer/memory because you would overwrite result with what MyObj() returns.
I do not really think so.
result[] = newMyObj()
does copy the CONTENT of newMyObj() into result variable. So when he allocates mem for result in a correct way with alloc() (I mentioned the sizeof bug) he should have a valid pointer initialized to valid content, for example with x == 42. Of course he is responsible for deallocation of that object.