[Vm-dev] external addresses and callbacks (FFI+Alien merge)

Esteban Lorenzano estebanlm at gmail.com
Tue Sep 15 15:29:58 UTC 2015


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


More information about the Vm-dev mailing list