[squeak-dev] [BUG][FIX] Bug in WeakMessageSend

Juan Vuletich juan at jvuletich.org
Tue May 12 17:39:18 UTC 2009


Hi Folks,

I found a bug in WeakMessageSend that generates a DNU because of the 
message receiver being collected and disappearing. The culprits are 
#ensureReceiver and #ensureReceiverAndArguments . These methods ensure 
nothing. It might happen (although not often) that the receiver or some 
argument is collected after this method is called, but before it is 
actually used.

The problem happens in Squeak 3.10, Pharo-10243, and Cuis.

Please take a look. Also take a look at my proposed solution. I'm not 
sure, maybe some will object keeping an artificial reference to an 
object that could have been collected otherwise, eve if it is just for 
the time of a message send... Anyway, comments welcome.

Cheers,
Juan Vuletich
-------------- next part --------------
'From Squeak3.7 of ''4 September 2004'' [latest update: #5989] on 12 May 2009 at 11:02:25 am'!

!WeakMessageSend methodsFor: 'evaluating' stamp: 'jmv 5/12/2009 10:59'!
value
	^ arguments isNil
		ifTrue: [
			self withEnsuredReceiverDo: [ :r | r perform: selector]]
		ifFalse: [
			self withEnsuredReceiverAndArgumentsDo: [ :r :a |
				r
					perform: selector
					withArguments: a]]! !

!WeakMessageSend methodsFor: 'evaluating' stamp: 'jmv 5/12/2009 11:00'!
valueWithArguments: anArray
	| argsToUse |
	
	"Safe to use, because they are built before ensureing receiver and args..."
	argsToUse _ self collectArguments: anArray.
	^self withEnsuredReceiverAndArgumentsDo: [ :r :a |
				r
					perform: selector
					withArguments: argsToUse ]! !

!WeakMessageSend methodsFor: 'evaluating' stamp: 'jmv 5/12/2009 11:01'!
valueWithEnoughArguments: anArray

	"call the selector with enough arguments from arguments and anArray"
	| args |
	args _ Array new: selector numArgs.
	args replaceFrom: 1
		to: ( arguments size min: args size)
		with: arguments
		startingAt: 1.
	args size > arguments size ifTrue: [
		args replaceFrom: arguments size + 1
			to: (arguments size + anArray size min: args size)
			with: anArray
			startingAt: 1.
	].

	"args is safe to use, because they are built before ensureing receiver and args..."
	^self withEnsuredReceiverAndArgumentsDo: [ :r :a |
				r
					perform: selector
					withArguments: args ]! !

!WeakMessageSend methodsFor: 'private' stamp: 'jmv 5/12/2009 10:54'!
withEnsuredReceiverAndArgumentsDo: aBlock
	"Grab real references to receiver and arguments. If they still exist, evaluate aBlock."

	"Return if my receiver has gone away"
	| r a |
	r _ self receiver.
	r ifNil: [ ^self ].

	
	"Make sure that my arguments haven't gone away"
	"arguments can not become nil. The extra care in #ensureReceiverAndArguments is wrong
	(BTW, the whole idea is wrong, that's why we do these new methods...)"
	a _ Array withAll: arguments.
	a with: shouldBeNil do: [ :arg :flag |
		arg ifNil: [ flag ifFalse: [ ^self ]]
	].

	aBlock value: r value: a! !

!WeakMessageSend methodsFor: 'private' stamp: 'jmv 5/12/2009 10:53'!
withEnsuredReceiverDo: aBlock
	"Grab a real reference to receive. If still there, evaluate aBlock."

	"Return if my receiver has gone away"
	| r |
	r _ self receiver.
	r ifNil: [ ^self ].

	aBlock value: r! !

WeakMessageSend removeSelector: #ensureReceiver!
WeakMessageSend removeSelector: #ensureReceiverAndArguments!


More information about the Squeak-dev mailing list