pharo-vm icon indicating copy to clipboard operation
pharo-vm copied to clipboard

Primitive error in #setPinnedInMemory: mapped incorrectly to the local variable

Open chisandrei opened this issue 3 years ago • 2 comments

Object>>#setPinnedInMemory: gets the error code from the primitive and if that error code is 'insufficient object memory', it tried again the primitive. However if there is an error, the ec variable is not initialised and instead the error is stored in the local variable requiredSize.

Tested in the latest Pharo 9

Pharo9.0.0
Build information: Pharo-9.0.0+build.1573.sha.0e09d756fc99383cbb498565200d9e5e9841ce11 (64 Bit)
Unnamed
CoInterpreter * VMMaker-tonel.1 uuid: 87063cbb-028e-0d00-bd44-58660a412f2c Nov 25 2021
StackToRegisterMappingCogit * VMMaker-tonel.1 uuid: 87063cbb-028e-0d00-bd44-58660a412f2c Nov 25 2021
v9.0.10 - Commit: db558908 - Date: 2021-11-25 11:12:35 +0100

Pharo 9.0.10 built on Nov 25 2021 19:19:50 Compiler: 4.2.1 Compatible Apple LLVM 11.0.3 (clang-1103.0.32.29)
VMMaker versionString v9.0.10 - Commit: db558908 - Date: 2021-11-25 11:12:35 +0100
CoInterpreter * VMMaker-tonel.1 uuid: 87063cbb-028e-0d00-bd44-58660a412f2c Nov 25 2021
StackToRegisterMappingCogit * VMMaker-tonel.1 uuid: 87063cbb-028e-0d00-bd44-58660a412f2c Nov 25 2021

This script reproduces the error

arrays := (1 to: 10000) collect: [ :i | (ByteArray new: (2 raisedToInteger: 16)) ].
arrays do: [ :each | each tfPointerAddress ]
Screenshot 2021-12-29 at 15 56 37 Screenshot 2021-12-29 at 15 56 50

If we remove the local variable and and add a halt the error is stored correctly in the ec variable:

setPinnedInMemory: aBoolean
	"The VM's garbage collector routinely moves objects as it reclaims and compacts
	 memory. But it can also pin an object so that it will not be moved around in memory,
    while still being reclamable by the garbage collector. This can make
	 it easier to pass objects out through the FFI. Objects are unpinnned when created.
	 This primitive either pins or unpins an object, and answers if it was already pinned.
	
	If there is not enough memory, I will try to find more memory and retry once."
	<primitive: 184 error: ec>
	
	ec = #'insufficient object memory'
		ifFalse: [ ^ self primitiveFailed ].
	
	Smalltalk garbageCollect < (self sizeInMemory * 2) ifTrue:
		[Smalltalk growMemoryByAtLeast: (self sizeInMemory * 2)].

	^ self retrySetPinnedInMemory: aBoolean
Screenshot 2021-12-29 at 16 00 25

chisandrei avatar Dec 29 '21 15:12 chisandrei

Great, so in our case, we probably just reached limit of currently allocated space and if the error code check would be correct, it would pass without us noticing anything else than a short lag.

pavel-krivanek avatar Dec 29 '21 15:12 pavel-krivanek

I'm wondering if other methods that rely on primitives could be affected by this problem. We are seeing from time to time crashes that look like below that seem to involve a primitive failure:

Most recent primitives
**PrimitiveFailure**
getSystemAttribute:
**PrimitiveFailure**
**PrimitiveFailure**
getSystemAttribute:
**PrimitiveFailure**
**PrimitiveFailure**
getSystemAttribute:
**PrimitiveFailure**
**PrimitiveFailure**
getSystemAttribute:
**PrimitiveFailure**
**PrimitiveFailure**

Currently there seem to be three methods that rely on the primitive error code and use temporaries:

  • Object>>setPinnedInMemory:
  • Object>>clone
  • Array>>elementsExchangeIdentityWith:
Screenshot 2022-01-06 at 14 03 18

chisandrei avatar Jan 06 '22 13:01 chisandrei