FFI problem: too many arguments

nicolas cellier ncellier at ifrance.com
Sat Feb 18 22:18:34 UTC 2006


I propose a patch in the Parser to check externalFunction number of arguments 
against method selector number of arguments and notify the user in case of 
mismatch.

Current Parser implementation does silently accept the method. If there is a 
mismatch, the primitive 120 (external call) will fail at execution time... 
very lately in my opinion, and hard to debug...

This correction is for 3.8.
Some of the changed methods have been redefined in 3.9, so this patch does not 
apply to 3.9, but has to be rewritten (easy).
-------------- next part --------------
'From Squeak3.8 of ''5 May 2005'' [latest update: #6665] on 18 February 2006 at 11:07:40 pm'!

!Parser methodsFor: 'expression types' stamp: 'nice 2/18/2006 23:05'!
method: doit context: ctxt encoder: encoderToUse
	" pattern [ | temporaries ] block => MethodNode."

	| sap blk prim temps messageComment methodNode |
	encoder := encoderToUse.
	sap := self pattern: doit inContext: ctxt.
	"sap={selector, arguments, precedence}"
	(sap at: 2) do: [:argNode | argNode isArg: true].
	temps := self temporariesIn: (sap at: 1).
	messageComment := currentComment.
	currentComment := nil.
	prim := doit ifTrue: [0] ifFalse: [self primitiveSelector: (sap at: 1) numArgs: (sap at: 2) size].
	self statements: #() innerBlock: doit.
	blk := parseNode.
	doit ifTrue: [blk returnLast]
		ifFalse: [blk returnSelfIfNoOther].
	hereType == #doIt ifFalse: [^self expected: 'Nothing more'].
	self interactive ifTrue: [self removeUnusedTemps].
	methodNode := self newMethodNode comment: messageComment.
	^ methodNode
		selector: (sap at: 1)
		arguments: (sap at: 2)
		precedence: (sap at: 3)
		temporaries: temps
		block: blk
		encoder: encoder
		primitive: prim! !

!Parser methodsFor: 'primitives' stamp: 'nice 2/18/2006 23:02'!
externalFunctionDeclarationSelector: methodSelector numArgs: numArg
	"Parse the function declaration for a call to an external library.
	Smalltalk method is known to have numArg arguments.
	Notify user if the function number of arguments mismatch."
	| descriptorClass callType retType externalName args argType module fn |
	descriptorClass := Smalltalk at: #ExternalFunction ifAbsent:[nil].
	descriptorClass == nil ifTrue:[^0].
	callType := descriptorClass callingConventionFor: here.
	callType == nil ifTrue:[^0].
	"Parse return type"
	self advance.
	retType := self externalType: descriptorClass.
	retType == nil ifTrue:[^self expected:'return type'].
	"Parse function name or index"
	externalName := here.
	(self match: #string) 
		ifTrue:[externalName := externalName asSymbol]
		ifFalse:[(self match:#number) ifFalse:[^self expected:'function name or index']].
	(self matchToken:'(' asSymbol) ifFalse:[^self expected:'argument list'].
	args := WriteStream on: Array new.
	[here == #')'] whileFalse:[
		argType := self externalType: descriptorClass.
		argType == nil ifTrue:[^self expected:'argument'].
		argType isVoid & argType isPointerType not ifFalse:[args nextPut: argType].
	].
	(self matchToken:')' asSymbol) ifFalse:[^self expected:')'].
	(self matchToken: 'module:') ifTrue:[
		module := here.
		(self match: #string) ifFalse:[^self expected: 'String'].
		module := module asSymbol].
	"Check number of arguments and notify if interactive"
	args contents size = numArg
		ifFalse:
			[self interactive
				ifTrue:[^self notify: 'Number of external function arguments do not match selector number of arguments']
				ifFalse:[Transcript 
					show: '(Number of external function arguments do not match selector number of arguments in "' , encoder classEncoding printString , '>>' , methodSelector printString , '")']].
	Smalltalk at: #ExternalLibraryFunction ifPresent:[:xfn|
		fn := xfn name: externalName 
				module: module 
				callType: callType
				returnType: retType
				argumentTypes: args contents.
		self allocateLiteral: fn.
	].

	^120! !

!Parser methodsFor: 'primitives' stamp: 'nice 2/18/2006 23:03'!
primitiveDeclarationsSelector: methodSelector numArgs: numArg
	| prim module |
	(self matchToken: 'primitive:') ifFalse:[^self externalFunctionDeclarationSelector: methodSelector numArgs: numArg].
	prim := here.
	(self match: #number) ifTrue:[^prim].	"Indexed primitives"
	(self match: #string) ifFalse:[^self expected:'Integer or String'].
	(self matchToken: 'module:') ifTrue:[
		module := here.
		(self match: #string) ifFalse:[^self expected: 'String'].
		module := module asSymbol].
	(self allocateLiteral: (Array with: module with: prim asSymbol with: 0 with: 0)).
	^117! !

!Parser methodsFor: 'primitives' stamp: 'nice 2/18/2006 23:03'!
primitiveSelector: methodSelector numArgs: numArg
	| n |
	(self matchToken: #<) ifFalse: [^ 0].
	n := self primitiveDeclarationsSelector: methodSelector numArgs: numArg.
	(self matchToken: #>) ifFalse: [^ self expected: '>'].
	^ n! !



More information about the Squeak-dev mailing list