Trying to dereference a pointer to an unmanaged object that was defined in a function scope gives an invalid address.
Some checks that were done:
deinit indicates that the object is not deinitialized before the end of the program.This can definitely be distilled further, such as removing the integer casts, for example. I might take a stab at doing this when I get a chance.
Source Code:
proc main() {
writeln('(main) makeC');
var ptr = makeC();
writeln('(main) ptr: ', ptr);
var cPtr = __primitive("cast", c_ptr(unmanaged C), ptr);
writeln('(main) cPtr: ', cPtr);
var c = cPtr.deref();
writeln('(main) c: ', c);
writeln('(main) writeC');
writeC(ptr);
}
proc makeC() : int {
var x = new unmanaged C(2);
writeln('(makeC) x: ', x);
var ptr = c_ptrTo(x):int;
writeln('(makeC) ptr: ', ptr);
return ptr;
}
proc writeC(ptr : int) {
writeln('(writeC) ptr: ', ptr);
var cPtr = __primitive("cast", c_ptr(unmanaged C), ptr);
writeln('(writeC) cPtr: ', cPtr);
var c = cPtr.deref();
writeln('(writeC) c: ', c);
}
class C {
var x : int = 1;
proc deinit() {
writeln('C.deinit() called');
}
}
Compile command:
chpl repro.chpl
Execution command:
Here is the local output on my machine, but note that running with valgrind on linux yields a seg fault at the first dereference outside of makeC:
(main) makeC
(makeC) x: {x = 2}
(makeC) ptr: 4513062368
(main) ptr: 4513062368
(main) cPtr: 0x10cffdde0
(main) c: {x = 2} # <--- seg faults when running with valgrind
(main) writeC
(writeC) ptr: 4513062368
(writeC) cPtr: 0x10cffdde0
(writeC) c: nil
chpl --version: chpl version 1.21.0 pre-release (f3e74adea4)Marked as user issue since @npadmana ran into this.
FYI @mppf - this is the issue we were chatting about offline.
The code is wrong.
proc makeC() : int {
var x = new unmanaged C(2);
writeln('(makeC) x: ', x);
var ptr = c_ptrTo(x):int;
writeln('(makeC) ptr: ', ptr);
return ptr;
}
This returns a pointer to a local variable (as an integer). You might imagine in being like this C code:
long makeC() {
void* x = malloc(16);
return (long) &x;
}
Here is a corrected version of the example that runs correctly with valgrind:
proc main() {
writeln('(main) makeC');
var ptr = makeC();
writeln('(main) ptr: ', ptr);
var c = (ptr:unmanaged C?)!;
writeln('(main) c: ', c);
writeln('(main) writeC');
writeC(ptr);
}
proc makeC() : c_void_ptr {
var x = new unmanaged C(2);
writeln('(makeC) x: ', x);
var ptr = x:c_void_ptr;
writeln('(makeC) ptr: ', ptr);
return ptr;
}
proc writeC(ptr : c_void_ptr) {
writeln('(writeC) ptr: ', ptr);
var c = (ptr:unmanaged C?)!;
writeln('(writeC) c: ', c);
}
class C {
var x : int = 1;
proc deinit() {
writeln('C.deinit() called');
}
}
Thanks @mppf!
@npadmana - I've ported Michael's example to the integer-as-pointer use-case you had in mind originally, and confirmed it works as expected:
proc main() {
writeln('(main) makeC');
var ptr = makeC();
writeln('(main) writeC');
writeC(ptr);
}
proc makeC() : int {
var x = new unmanaged C(2);
writeln('(makeC) x: ', x);
var ptr = x:c_void_ptr;
writeln('(makeC) ptr: ', ptr);
return ptr:int;
}
proc writeC(intPtr : int) {
var ptr = __primitive("cast", c_void_ptr, intPtr);
writeln('(writeC) ptr: ', ptr);
var x = (ptr:unmanaged C?)!;
writeln('(writeC) x: ', x);
}
class C {
var x : int = 1;
}
> ./pointer-as-int
(main) makeC
(makeC) x: {x = 2}
(makeC) ptr: 0x104010310
(main) writeC
(writeC) ptr: 0x104010310
(writeC) x: {x = 2}
I'm going to close this issue, but let me know if you run into any other problems related to this.
Thanks, Michael!!!
I wonder if this would be an interesting example to add either to SO, or to the technote on interoperability.
Most helpful comment
The code is wrong.
This returns a pointer to a local variable (as an integer). You might imagine in being like this C code:
Here is a corrected version of the example that runs correctly with valgrind: