Hi,
I’m working on merge FFI with Alien as a way to provide a single callback mechanism (I already talked with Eliot and he agrees this is the way to go in the future). That means review certain stuff, a couple of them I already submitted in my last commit. Now I have this problem. This is my example method:
exampleCqsort | cb rand values orig sort |
rand := Random new. values := FFIExternalArray newType: 'double' size: 100. 1 to: 100 do: [ :i| values at: i put: rand next ]. orig := (1 to: 100) collect: [:i| values at: i]. cb := Callback signature: #(int (*)(const void *, const void *)) block: [ :arg1 :arg2 | ((arg1 doubleAt: 1) - (arg2 doubleAt: 1)) sign ]. [ self primQsort: values getHandle with: 100 with: values type typeSize with: cb thunk. sort := values asArray ] ensure: [ values free ]. ^orig -> sort
primQsort: array with: count with: size with: compare <cdecl: void 'qsort' (void* ulong ulong void*) module: 'libc’> ^ self primitiveFailed
… that basically works. But this depends on this method in Callback:
voidstarvoidstarRetint: callbackContext sp: spAlien <signature: #(int (*)(const void *, const void *)) abi: 'IA32'> | value | value := block value: (Alien forPointer: (spAlien unsignedLongAt: 1)) value: (Alien forPointer: (spAlien unsignedLongAt: 5)). ^ callbackContext wordResult: value
And I want to remove Alien from the equation (there will still be some… and there will be the primitives of course, but I want to reduce their use at the minimum for obvious reasons: hide the extra complexity to users). So this function would be something like this instead:
voidstarvoidstarRetint: callbackContext sp: spAlien <signature: #(int (*)(const void *, const void *)) abi: 'IA32'> | value | value := block value: (spAlien pointerAt: 1) “It will answer an ExternalAddress” value: ((spAlien pointerAt: 5). “It will answer an ExternalAddress” ^ callbackContext wordResult: value
So… this *should* work but it doesn’t because in primitiveFFIDoubleAt: I have a call to
ffiAddressOf: rcvr startingAt: byteOffset size: byteSize
who mades this check:
"don't you dare to read from object memory!" (addr == 0 or:[interpreterProxy isInMemory: addr]) ifTrue:[^interpreterProxy primitiveFail].
and well… since I’m calling things from a callback the #isInMemory: method fails.
If I took out that method everything works ok and since the equivalent IA32ABIPlugin does not have that check I can suppose it is ok to remove the validation.
But! Since there was that comment ("don't you dare to read from object memory!”)… I’m afraid I can be making a mistake.
What do you think?
Esteban
On Tue, Sep 15, 2015 at 8:29 AM, Esteban Lorenzano estebanlm@gmail.com wrote:
Hi,
I’m working on merge FFI with Alien as a way to provide a single callback mechanism (I already talked with Eliot and he agrees this is the way to go in the future). That means review certain stuff, a couple of them I already submitted in my last commit. Now I have this problem. This is my example method:
exampleCqsort | cb rand values orig sort |
rand := Random new. values := FFIExternalArray newType: 'double' size: 100. 1 to: 100 do: [ :i| values at: i put: rand next ]. orig := (1 to: 100) collect: [:i| values at: i]. cb := Callback signature: #(int (*)(const void *, const void *)) block: [ :arg1 :arg2 | ((arg1 doubleAt: 1) - (arg2
doubleAt: 1)) sign ]. [ self primQsort: values getHandle with: 100 with: values type typeSize with: cb thunk. sort := values asArray ] ensure: [ values free ]. ^orig -> sort
primQsort: array with: count with: size with: compare <cdecl: void 'qsort' (void* ulong ulong void*) module: 'libc’> ^ self primitiveFailed
… that basically works. But this depends on this method in Callback:
voidstarvoidstarRetint: callbackContext sp: spAlien <signature: #(int (*)(const void *, const void *)) abi: 'IA32'> | value |
value := block value: (Alien forPointer: (spAlien unsignedLongAt:
1)) value: (Alien forPointer: (spAlien unsignedLongAt: 5)). ^ callbackContext wordResult: value
And I want to remove Alien from the equation (there will still be some… and there will be the primitives of course, but I want to reduce their use at the minimum for obvious reasons: hide the extra complexity to users). So this function would be something like this instead:
voidstarvoidstarRetint: callbackContext sp: spAlien <signature: #(int (*)(const void *, const void *)) abi: 'IA32'> | value |
value := block value: (spAlien pointerAt: 1) “It will answer an
ExternalAddress” value: ((spAlien pointerAt: 5). “It will answer an ExternalAddress” ^ callbackContext wordResult: value
So… this *should* work but it doesn’t because in primitiveFFIDoubleAt: I have a call to
ffiAddressOf: rcvr startingAt: byteOffset size: byteSize
who mades this check:
"don't you dare to read from object memory!" (addr == 0 or:[interpreterProxy isInMemory: addr]) ifTrue:[^interpreterProxy primitiveFail].
and well… since I’m calling things from a callback the #isInMemory: method fails.
If I took out that method everything works ok and since the equivalent IA32ABIPlugin does not have that check I can suppose it is ok to remove the validation.
But! Since there was that comment ("don't you dare to read from object memory!”)… I’m afraid I can be making a mistake.
What do you think?
The elements of your FFIExternalArray should be in malloc's heap, not in the Smalltalk heap, so the check should pass.
On 18 Sep 2015, at 05:55, Ryan Macnak rmacnak@gmail.com wrote:
On Tue, Sep 15, 2015 at 8:29 AM, Esteban Lorenzano <estebanlm@gmail.com mailto:estebanlm@gmail.com> wrote:
Hi,
I’m working on merge FFI with Alien as a way to provide a single callback mechanism (I already talked with Eliot and he agrees this is the way to go in the future). That means review certain stuff, a couple of them I already submitted in my last commit. Now I have this problem. This is my example method:
exampleCqsort | cb rand values orig sort |
rand := Random new. values := FFIExternalArray newType: 'double' size: 100. 1 to: 100 do: [ :i| values at: i put: rand next ]. orig := (1 to: 100) collect: [:i| values at: i]. cb := Callback signature: #(int (*)(const void *, const void *)) block: [ :arg1 :arg2 | ((arg1 doubleAt: 1) - (arg2 doubleAt: 1)) sign ]. [ self primQsort: values getHandle with: 100 with: values type typeSize with: cb thunk. sort := values asArray ] ensure: [ values free ]. ^orig -> sort
primQsort: array with: count with: size with: compare <cdecl: void 'qsort' (void* ulong ulong void*) module: 'libc’> ^ self primitiveFailed
… that basically works. But this depends on this method in Callback:
voidstarvoidstarRetint: callbackContext sp: spAlien <signature: #(int (*)(const void *, const void *)) abi: 'IA32'> | value |
value := block value: (Alien forPointer: (spAlien unsignedLongAt: 1)) value: (Alien forPointer: (spAlien unsignedLongAt: 5)). ^ callbackContext wordResult: value
And I want to remove Alien from the equation (there will still be some… and there will be the primitives of course, but I want to reduce their use at the minimum for obvious reasons: hide the extra complexity to users). So this function would be something like this instead:
voidstarvoidstarRetint: callbackContext sp: spAlien <signature: #(int (*)(const void *, const void *)) abi: 'IA32'> | value |
value := block value: (spAlien pointerAt: 1) “It will answer an ExternalAddress” value: ((spAlien pointerAt: 5). “It will answer an ExternalAddress” ^ callbackContext wordResult: value
So… this *should* work but it doesn’t because in primitiveFFIDoubleAt: I have a call to
ffiAddressOf: rcvr startingAt: byteOffset size: byteSize
who mades this check:
"don't you dare to read from object memory!" (addr == 0 or:[interpreterProxy isInMemory: addr]) ifTrue:[^interpreterProxy primitiveFail].
and well… since I’m calling things from a callback the #isInMemory: method fails.
If I took out that method everything works ok and since the equivalent IA32ABIPlugin does not have that check I can suppose it is ok to remove the validation.
But! Since there was that comment ("don't you dare to read from object memory!”)… I’m afraid I can be making a mistake.
What do you think?
The elements of your FFIExternalArray should be in malloc's heap, not in the Smalltalk heap, so the check should pass.
it doesn’t, that’s the point. also IMO that’s incorrect: if I want to read some structure in smalltalk memory who will be passed as a ByteArray (bah, a byte*) to FFI, that check will fail too… and that’s incorrect. and since that check was removed in IA32ABIPlugin, I think this has been taken into account.
Esteban
vm-dev@lists.squeakfoundation.org