Skip to content

Commit

Permalink
Add framework and tests for compilation/code creation inside a sandbox
Browse files Browse the repository at this point in the history
Open issues:

* #testClassComment fails because accesses to the FilePlugin are not allowed - we could either create an exception for the sources file or process these requests outside of the sanfbox.
* #testSubclass crashes the VM because of something we are doing wrong/differently than normal Trunk during the behavior creation. See: http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-December/217860.html
  • Loading branch information
LinqLover committed Dec 29, 2021
1 parent 02fb71e commit 432e301
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*SimulationStudio-Sandbox-compiling-pseudo override
dontLogCompiledSourcesDuring: aBlock

| previous |
previous := self logCompiledSources.
self logCompiledSources: false.
^ aBlock ensure: [self logCompiledSources: previous]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"class" : {
"dontLogCompiledSourcesDuring:" : "ct 12/28/2021 22:54" },
"instance" : {
} }
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
"name" : "ClassDescription" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
support
disableLoggingAndNotifyingDuringCompilation: aBlock

^ SystemChangeNotifier uniqueInstance doSilently:
[ClassDescription dontLogCompiledSourcesDuring: aBlock]
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
evaluating
basicEvaluate: aBlock
"Evaluate aBlock in a the receiver, isolating it from the rest of the image, and answer the result as it is seen from the global perspective.
PRIVATE! Does not care about any exceptions that are signaled during the simulation, causing them to be handled still inside the sandbox, even if an exception handler has been defined outside of the sandbox stack. Depending on the configuration of the sandbox and your image, this can mean that even the eventual pop-up of the debugger will be simulated and thus invisible to you! Usually, it is a better idea to use the public #evaluate: protocol instead."

^ (SandboxContext newFrom: thisContext)
sandbox: self;
runSimulated: aBlock contextAtEachStep: []
^ self basicEvaluate: aBlock contextAtEachStep: []
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
evaluating
basicEvaluate: aBlock contextAtEachStep: anotherBlock
"Evaluate aBlock in a the receiver, isolating it from the rest of the image. Evaluate anotherBlock with the current context prior to each instruction executed. Answer the result as it is seen from the global perspective.
PRIVATE! Does not care about any exceptions that are signaled during the simulation, causing them to be handled still inside the sandbox, even if an exception handler has been defined outside of the sandbox stack. Depending on the configuration of the sandbox and your image, this can mean that even the eventual pop-up of the debugger will be simulated and thus invisible to you! Usually, it is a better idea to use the public #evaluate: protocol instead."

^ (SandboxContext newFrom: thisContext)
sandbox: self;
runSimulated: aBlock contextAtEachStep: anotherBlock
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
evaluating
evaluate: aBlock contextAtEachStep: contextBlock ifFailed: failBlock
"Evaluate aBlock in a the receiver and answer the result, isolating it from the rest of the image. Evaluate anotherBlock with the current context prior to each instruction executed. If aBlock signals a failure, evaluate failBlock with that failure.
Example:
Sandbox evaluate: [1 / 0] ifFailed: [:ex | Transcript showln: ex description].
"

^ self
evaluate: aBlock
contextAtEachStep: contextBlock
on: Error, Warning, Halt
do: failBlock
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
evaluating
evaluate: aBlock contextAtEachStep: contextBlock on: exceptionHandler do: exceptionBlock
"Evaluate aBlock in the receiver, isolating it from the rest of the image. If aBlock signals an exception that can handled by the exceptionHandler, evaluate exceptionBlock with it. Evaluate contextBlock with the current context prior to each instruction executed. Answer the simulated value of aBlock.
NOTE: Unhandled errors raised by aBlock will bubble up along the sender stack, but still, all handling is simulated in the sandbox until the exception will have been resumed. Depending on the configuration of the sandbox and your image, this can mean that even the pop-up of the eventual debugger will be simulated and thus invisible to you! Thus make sure to pass all relevant exceptions with this message.
Example:
Sandbox evaluate: [1 / 0] on: ZeroDivide do: [:ex | Transcript showln: ex description].
Sandbox new
evaluate: [2 / 3]
contextAtEachStep: [:ctx | Transcript showln: {ctx. ctx pc}]
on: ZeroDivide
do: [:ex | Transcript showln: ex description] .
""Use with CAUTION and check your image via the ProcessBrowser afterwards""
Sandbox evaluate: [self halt] on: ZeroDivide do: [:ex | Transcript showln: ex description].
"

| result exception |
self
basicEvaluate: [[result := aBlock value]
on: exceptionHandler
do: [:ex | exception := ex]]
contextAtEachStep: contextBlock.

(self basicEvaluate: [exception]) ifNotNil: [:ex | ^ exceptionBlock cull: ex].

^ self readableObjectFor: (self basicEvaluate: [result])
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ evaluate: aBlock ifFailed: failBlock

^ self
evaluate: aBlock
on: Error, Warning, Halt
do: failBlock
contextAtEachStep: []
ifFailed: failBlock
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ evaluate: aBlock on: exceptionHandler do: exceptionBlock
Sandbox evaluate: [self halt] on: ZeroDivide do: [:ex | Transcript showln: ex description].
"

| result exception |
self basicEvaluate: [[result := aBlock value]
^ self
evaluate: aBlock
contextAtEachStep: []
on: exceptionHandler
do: [:ex | exception := ex]].

(self basicEvaluate: [exception]) ifNotNil: [:ex | ^ exceptionBlock cull: ex].

^ self readableObjectFor: (self basicEvaluate: [result])
do: exceptionBlock
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"class" : {
"debug:" : "ct 3/5/2021 21:17",
"disableLoggingAndNotifyingDuringCompilation:" : "ct 12/28/2021 22:56",
"evaluate:" : "ct 3/6/2021 13:12",
"evaluate:ifFailed:" : "ct 3/6/2021 13:12",
"evaluate:on:do:" : "ct 3/6/2021 13:12",
Expand All @@ -9,13 +10,16 @@
"streamSelectorsFor:arguments:thatAnswer:" : "ct 11/13/2021 16:11" },
"instance" : {
"addObject:" : "ct 3/22/2021 17:51",
"basicEvaluate:" : "ct 11/13/2021 16:12",
"basicEvaluate:" : "ct 11/15/2021 23:05",
"basicEvaluate:contextAtEachStep:" : "ct 11/15/2021 23:05",
"debug:" : "ct 3/5/2021 21:25",
"elements:exchangeIdentityWith:" : "ct 1/10/2021 21:03",
"elements:forwardIdentityTo:copyHash:" : "ct 3/4/2021 20:19",
"evaluate:" : "ct 3/6/2021 13:10",
"evaluate:ifFailed:" : "ct 3/6/2021 13:10",
"evaluate:on:do:" : "ct 3/6/2021 12:45",
"evaluate:contextAtEachStep:ifFailed:" : "ct 11/15/2021 23:11",
"evaluate:contextAtEachStep:on:do:" : "ct 11/15/2021 23:10",
"evaluate:ifFailed:" : "ct 11/15/2021 23:12",
"evaluate:on:do:" : "ct 11/15/2021 23:11",
"exportMemory" : "ct 3/6/2021 01:38",
"hashFor:" : "ct 1/10/2021 21:40",
"importMemory:" : "ct 3/6/2021 01:39",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
support
disableLoggingAndNotifyingDuringCompilation: aBlock

^ SystemChangeNotifier uniqueInstance doSilently:
[ClassDescription dontLogCompiledSourcesDuring: aBlock]
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"class" : {
"benchmarkSandboxVsSandbox2" : "ct 11/13/2021 17:25",
"debug:" : "ct 11/13/2021 16:11",
"disableLoggingAndNotifyingDuringCompilation:" : "ct 12/29/2021 02:00",
"evaluate:" : "ct 11/13/2021 16:12",
"evaluate:ifFailed:" : "ct 11/13/2021 16:12",
"evaluate:on:do:" : "ct 11/13/2021 16:12",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
accessing
someToken

^ UUID nilUUID
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
tests
testClassComment

| comment |
comment := self sandboxClass evaluate: [Object comment].
self assert: (comment includesSubstring: 'root').
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
tests
testCompile

| result token |
self assert: UUID nilUUID equals: self someToken.

token := UUID new asString.
result := self sandboxClass disableLoggingAndNotifyingDuringCompilation:
[self sandboxClass evaluate: [
self class compile: 'someToken ^' , token printString.
self someToken]].

self assert: token equals: result.
self assert: UUID nilUUID equals: self someToken.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
tests
testSubclass

| name |
self fail: #forLater. "Currently, simulation of subclassing will crash the VM. See: http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-December/217860.html"

name := #SandboxTestClass , UUID new asString asLegalSelector asCamelCase.

self shouldnt: (Smalltalk hasClassNamed: name).

self sandboxClass disableLoggingAndNotifyingDuringCompilation:
[self sandboxClass evaluate: [ | class instance |
class := Object
subclass: name asSymbol
instanceVariableNames: 'griffle plonk'
classVariableNames: ''
poolDictionaries: ''
category: 'SimulationStudio-Tests-UserObjects'.
instance := class new.

self
assert: (instance isKindOf: class);
assert: (instance class == class);
assert: (thisContext objectClass: instance) == class.

class compile: 'foo ^ ' , self selector printString.

self assert: self selector printString equals: instance foo]].

self deny: (Smalltalk hasClassNamed: name).
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
},
"instance" : {
"sandboxClass" : "ct 11/13/2021 16:05",
"someToken" : "ct 12/28/2021 23:00",
"testBitBlt" : "ct 11/13/2021 00:00",
"testCannotUsurpExecution" : "ct 11/13/2021 00:01",
"testClassComment" : "ct 12/29/2021 01:57",
"testCompile" : "ct 12/28/2021 23:00",
"testFindSelectors" : "ct 12/27/2021 00:32",
"testIdentityHashConstant" : "ct 11/13/2021 00:01",
"testMemoryHashes" : "ct 11/13/2021 00:01",
"testMemoryObjects" : "ct 11/13/2021 00:01",
"testOperationForbidden" : "ct 11/13/2021 00:01",
"testRecursiveSandbox" : "ct 11/13/2021 00:01",
"testSandbox" : "ct 11/13/2021 00:01",
"testSandbox2" : "ct 11/14/2021 17:55" } }
"testSandbox2" : "ct 11/14/2021 17:55",
"testSubclass" : "ct 12/29/2021 19:15" } }

0 comments on commit 432e301

Please sign in to comment.