Hi Igor,
On Mon, Sep 7, 2009 at 10:29 AM, Igor Stasenko <[hidden email]> wrote: > > 2009/9/7 Bert Freudenberg <[hidden email]>: > > > > On 07.09.2009, at 18:40, Randal L. Schwartz wrote: > > > >>>>>>> "Igor" == Igor Stasenko <[hidden email]> writes: > >> > >> Igor> Here is the default implementation of > >> > >> Object> debugPrintOn: aStream > >> Igor> ^ self printOn: aStream > >> > >> I like it, but I don't like the name. It conjurs up the idea of debugging > >> the #printOn: method itself. > >> > >> maybe #printForDebuggerOn: ? > > > > > > It matches the other methods like #longPrintOn: though. > > > > Also that would imply only the debugger invokes it, when it's clearly > > appropriate for any purpose. > > > > However, apart from this bike shedding ;) do others think it's a good idea > > in general? IMHO #printOn: is primarily used for debugging anyway so I > > wouldn't really expect a separate debug print method to be needed. Debugging > > transparent proxies isn't for the faint-of-heart anyway, so these developers > > can adapt their tools and proxies I would guess. OTOH there is precedence in > > e.g. #asExplorerString, which exists solely to get rid of the quotes > > enclosing strings for aesthetic reasons ... > > > > I agree with you Bert, that we should consider if its really necessary. > While #printOn: is used by most code for debugging, some of the code > using it to serialize object to textual stream, so the #printOn: usage > is much more generic than just debugging. > > As for debugging the transparent proxies - yes you can make own > tools.. but this means reimplementing/hacking > other tools , like debugger, inspector and so on, which will probably > end up with similar solution to what i proposing. > > For example, there was a point of discrepancy with debugging the code > which uses Magma. > The magma forwarding proxy reifying the object once the first real > message is sent to it. > And the problem with such a proxy, that you can't use them in certain > situations, like: > > self perform: aSelectorProxied with: #foo > > because #perform doesn't sends the messages to aSelectorProxied and > primitive fails. But then, when you entering the debugger and trying > to figure out why its not working - a proxy becomes a real object when > it printed out.. and so you can't debug the error using debugger. > Which leaves you to wonder, why code works in debugger, but not > working at run time :) VisualWorks a while back. The idea is to add a set of mirror primitives, so called because they do reflection, to ContextPart. These primitives implement the basic operations of the object model needed for execution simulation, fetching an object's class, accessing its named and indexed instance variables, and the number of indexed instance variables, sending a message, but they take the object operated on as a parameter and so do function without sending messages to that object. These primitives are then used by the execution simulation machinery to correctly simulate the execution of the virtual machine irrespective of the class and/or messages implemented by the receiver. For example, (eschewing HTML for Bert's contentment) ContextPart methods for mirror primitives object: anObject instVarAt: anIndex "Primitive. Answer a fixed variable in an object. The numbering of the variables corresponds to the named instance variables. Fail if the index is not an Integer or is not the index of a fixed variable. Essential for the debugger. See Object documentation whatIsAPrimitive." <primitive: 73> "Access beyond fixed variables." ^self object: anObject basicAt: anIndex - (self objectClass: anObject) instSize object: anObject instVarAt: anIndex put: aValue "Primitive. Store a value into a fixed variable in the argument anObject. The numbering of the variables corresponds to the named instance variables. Fail if the index is not an Integer or is not the index of a fixed variable. Answer the value stored as the result. Using this message violates the principle that each object has sovereign control over the storing of values into its instance variables. Essential for the debugger. See Object documentation whatIsAPrimitive." <primitive: 74> "Access beyond fixed fields" ^self object: anObject basicAt: anIndex - (self objectClass: anObject) instSize put: aValue ContextPart methods for instruction decoding pushReceiverVariable: offset "Simulate the action of bytecode that pushes the contents of the receiver's instance variable whose index is the argument, index, on the top of the stack." self push: (self object: self receiver instVarAt: offset + 1) popIntoReceiverVariable: offset "Simulate the action of bytecode that removes the top of the stack and stores it into an instance variable of my receiver." self object: self receiver instVarAt: offset + 1 put: self pop storeIntoReceiverVariable: offset "Simulate the action of bytecode that stores the top of the stack into an instance variable of my receiver." self object: self receiver instVarAt: offset + 1 put: self top The attached change set for the image level code is also conflated with changes that allow the debugger to set the primitive error code correctly. The VM also needs to implement the primitives. If the order of the arguments are the same as those of the corresponding non-reflective primitive (e.g. aContext object: theReceiver instVarAt: index put: value has the same order as theReceiver instVarAt: index put: value) and the primitive pops back the stack using self pop: argumentCount + 1, one can use the same VM primitive implementations as the non-reflective ones and so avoid needing extra primitives. However, not all primitives are correctly implemented; e.g. at: and at:put: are, but size is not. So before we can use this there is some work to do in the standard VMs. I'm attaching here the implementation in the Stack VM which will require some back porting to the standard VM. None of these changes has performance implications because the special selector impelmentations of at: at:put: size and #== are not affected. With the above changes one can safely step through code that uses proxies that do not inherit from Object, or even ProtoObject. I still need to implement a PrimitiveObjectInspector, or use the mirror primitives in implementing the Inspector. However, there is one more important thing needed in the debugger which these changes do not address and that is the value of Processor activeProcess within the debugger. e.g. "print it" the following: | thisProcessOutsideTheDebugger thisProcessInsideTheDebugger | thisProcessOutsideTheDebugger := Processor activeProcess. self halt. thisProcessInsideTheDebugger := Processor activeProcess. 'Send to here (Into) then proceed'. thisProcessOutsideTheDebugger == thisProcessInsideTheDebugger This will potentially break debugging of servers that maintain process pools. Andreas has proposed a very simple fix for this. Add an instance variable to Process called, e.g. effectiveProcess, which is nil in normal processes. When the debugger runs it sets effectiveProcess to that of the process which it is debugging and Processor activeProcess is implemented as something like ProcessorScheduler methods for accessing activeProcess ^activeProcess effectiveProcess ifNil: [activeProcess] I'll try and get round to this soon. I'm posting this rather than integrating because a) the VMs need to get updated before we can use the image level code and, b) the VM folks need code to test their VMs with. I'm happy to integrate the image-level changes once the VMs have been upgraded. best Eliot > > > > > - Bert - > > > > > -- > Best regards, > Igor Stasenko AKA sig. > |
On 07.09.2009, at 20:56, Eliot Miranda wrote:
> > I have fixes for this integrated in Qwaq. This is work I did for > VisualWorks a while back. The idea is to add a set of mirror > primitives, so called because they do reflection, to ContextPart. > These primitives implement the basic operations of the object model > needed for execution simulation, fetching an object's class, accessing > its named and indexed instance variables, and the number of indexed > instance variables, sending a message, but they take the object > operated on as a parameter and so do function without sending messages > to that object. Wouldn't that break encapsulation in a way we never had to before? - Bert - |
In reply to this post by Eliot Miranda-2
On Mon, Sep 7, 2009 at 11:56 AM, Eliot Miranda<[hidden email]> wrote:
> Hi Igor, > > On Mon, Sep 7, 2009 at 10:29 AM, Igor Stasenko <[hidden email]> wrote: >> >> 2009/9/7 Bert Freudenberg <[hidden email]>: >> > >> > On 07.09.2009, at 18:40, Randal L. Schwartz wrote: >> > >> >>>>>>> "Igor" == Igor Stasenko <[hidden email]> writes: >> >> >> >> Igor> Here is the default implementation of >> >> >> >> Object> debugPrintOn: aStream >> >> Igor> ^ self printOn: aStream >> >> >> >> I like it, but I don't like the name. It conjurs up the idea of debugging >> >> the #printOn: method itself. >> >> >> >> maybe #printForDebuggerOn: ? >> > >> > >> > It matches the other methods like #longPrintOn: though. >> > >> > Also that would imply only the debugger invokes it, when it's clearly >> > appropriate for any purpose. >> > >> > However, apart from this bike shedding ;) do others think it's a good idea >> > in general? IMHO #printOn: is primarily used for debugging anyway so I >> > wouldn't really expect a separate debug print method to be needed. Debugging >> > transparent proxies isn't for the faint-of-heart anyway, so these developers >> > can adapt their tools and proxies I would guess. OTOH there is precedence in >> > e.g. #asExplorerString, which exists solely to get rid of the quotes >> > enclosing strings for aesthetic reasons ... >> > >> >> I agree with you Bert, that we should consider if its really necessary. >> While #printOn: is used by most code for debugging, some of the code >> using it to serialize object to textual stream, so the #printOn: usage >> is much more generic than just debugging. >> >> As for debugging the transparent proxies - yes you can make own >> tools.. but this means reimplementing/hacking >> other tools , like debugger, inspector and so on, which will probably >> end up with similar solution to what i proposing. >> >> For example, there was a point of discrepancy with debugging the code >> which uses Magma. >> The magma forwarding proxy reifying the object once the first real >> message is sent to it. >> And the problem with such a proxy, that you can't use them in certain >> situations, like: >> >> self perform: aSelectorProxied with: #foo >> >> because #perform doesn't sends the messages to aSelectorProxied and >> primitive fails. But then, when you entering the debugger and trying >> to figure out why its not working - a proxy becomes a real object when >> it printed out.. and so you can't debug the error using debugger. >> Which leaves you to wonder, why code works in debugger, but not >> working at run time :) > > I have fixes for this integrated in Qwaq. This is work I did for > VisualWorks a while back. The idea is to add a set of mirror > primitives, so called because they do reflection, to ContextPart. > These primitives implement the basic operations of the object model > needed for execution simulation, fetching an object's class, accessing > its named and indexed instance variables, and the number of indexed > instance variables, sending a message, but they take the object > operated on as a parameter and so do function without sending messages > to that object. These primitives are then used by the execution > simulation machinery to correctly simulate the execution of the > virtual machine irrespective of the class and/or messages implemented > by the receiver. > > For example, (eschewing HTML for Bert's contentment) > > ContextPart methods for mirror primitives > object: anObject instVarAt: anIndex > "Primitive. Answer a fixed variable in an object. The numbering of the > variables corresponds to the named instance variables. Fail if the index > is not an Integer or is not the index of a fixed variable. Essential for the > debugger. See Object documentation whatIsAPrimitive." > > <primitive: 73> > "Access beyond fixed variables." > ^self object: anObject basicAt: anIndex - (self objectClass: anObject) instSize > > object: anObject instVarAt: anIndex put: aValue > "Primitive. Store a value into a fixed variable in the argument anObject. > The numbering of the variables corresponds to the named instance > variables. Fail if the index is not an Integer or is not the index of a > fixed variable. Answer the value stored as the result. Using this > message violates the principle that each object has sovereign control > over the storing of values into its instance variables. Essential for the > debugger. See Object documentation whatIsAPrimitive." > > <primitive: 74> > "Access beyond fixed fields" > ^self object: anObject basicAt: anIndex - (self objectClass: > anObject) instSize put: aValue > > ContextPart methods for instruction decoding > pushReceiverVariable: offset > "Simulate the action of bytecode that pushes the contents of the receiver's > instance variable whose index is the argument, index, on the top of the stack." > > self push: (self object: self receiver instVarAt: offset + 1) > > popIntoReceiverVariable: offset > "Simulate the action of bytecode that removes the top of the stack and > stores it into an instance variable of my receiver." > > self object: self receiver instVarAt: offset + 1 put: self pop > > storeIntoReceiverVariable: offset > "Simulate the action of bytecode that stores the top of the stack into an > instance variable of my receiver." > > self object: self receiver instVarAt: offset + 1 put: self top > > The attached change set for the image level code is also conflated > with changes that allow the debugger to set the primitive error code > correctly. > > > The VM also needs to implement the primitives. If the order of the > arguments are the same as those of the corresponding non-reflective > primitive (e.g. aContext object: theReceiver instVarAt: index put: > value has the same order as theReceiver instVarAt: index put: value) > and the primitive pops back the stack using self pop: argumentCount + > 1, one can use the same VM primitive implementations as the > non-reflective ones and so avoid needing extra primitives. > > However, not all primitives are correctly implemented; e.g. at: and > at:put: are, but size is not. So before we can use this there is some > work to do in the standard VMs. I'm attaching here the implementation > in the Stack VM which will require some back porting to the standard > VM. None of these changes has performance implications because the > special selector impelmentations of at: at:put: size and #== are not > affected. > > With the above changes one can safely step through code that uses > proxies that do not inherit from Object, or even ProtoObject. I still > need to implement a PrimitiveObjectInspector, or use the mirror > primitives in implementing the Inspector. However, there is one more > important thing needed in the debugger which these changes do not > address and that is the value of Processor activeProcess within the > debugger. e.g. "print it" the following: > > | thisProcessOutsideTheDebugger thisProcessInsideTheDebugger | > thisProcessOutsideTheDebugger := Processor activeProcess. > self halt. > thisProcessInsideTheDebugger := Processor activeProcess. > 'Send to here (Into) then proceed'. > thisProcessOutsideTheDebugger == thisProcessInsideTheDebugger > > This will potentially break debugging of servers that maintain process > pools. Andreas has proposed a very simple fix for this. Add an > instance variable to Process called, e.g. effectiveProcess, which is > nil in normal processes. When the debugger runs it sets > effectiveProcess to that of the process which it is debugging and > Processor activeProcess is implemented as something like > > ProcessorScheduler methods for accessing > activeProcess > ^activeProcess effectiveProcess ifNil: [activeProcess] > > I'll try and get round to this soon. deferring to its interruptedProcess for all execution. care to bang on the attached? The definition of process is probably wrong for your image so integrate that carefully. > > > I'm posting this rather than integrating because a) the VMs need to > get updated before we can use the image level code and, b) the VM > folks need code to test their VMs with. I'm happy to integrate the > image-level changes once the VMs have been upgraded. > > best > Eliot > >> >> > >> > - Bert - >> > >> >> >> -- >> Best regards, >> Igor Stasenko AKA sig. >> > effectiveProcess.st (3K) Download Attachment |
In reply to this post by Bert Freudenberg
On Mon, Sep 7, 2009 at 12:19 PM, Bert Freudenberg<[hidden email]> wrote:
> On 07.09.2009, at 20:56, Eliot Miranda wrote: >> >> I have fixes for this integrated in Qwaq. This is work I did for >> VisualWorks a while back. The idea is to add a set of mirror >> primitives, so called because they do reflection, to ContextPart. >> These primitives implement the basic operations of the object model >> needed for execution simulation, fetching an object's class, accessing >> its named and indexed instance variables, and the number of indexed >> instance variables, sending a message, but they take the object >> operated on as a parameter and so do function without sending messages >> to that object. > > Wouldn't that break encapsulation in a way we never had to before? If one dared use those primitives for anything other than simulating the VM then I suppose they're a little worse than instVarAt:put: and basicAt:put:, but not so much. I think it is much more dangerous to have a debugger that appears to be correct but breaks one's code in ways that are horribly difficult to understand. Note that both Self and Newspeak (and VisualWorks) take the mirror primitive approach. But there is certainly a security issue and one wants to medate access to the mirror primitives carefully. > > - Bert - > > > > |
On 07.09.2009, at 21:29, Eliot Miranda wrote: > On Mon, Sep 7, 2009 at 12:19 PM, Bert > Freudenberg<[hidden email]> wrote: >> On 07.09.2009, at 20:56, Eliot Miranda wrote: >>> >>> I have fixes for this integrated in Qwaq. This is work I did for >>> VisualWorks a while back. The idea is to add a set of mirror >>> primitives, so called because they do reflection, to ContextPart. >>> These primitives implement the basic operations of the object model >>> needed for execution simulation, fetching an object's class, >>> accessing >>> its named and indexed instance variables, and the number of indexed >>> instance variables, sending a message, but they take the object >>> operated on as a parameter and so do function without sending >>> messages >>> to that object. >> >> Wouldn't that break encapsulation in a way we never had to before? > > If one dared use those primitives for anything other than simulating > the VM then I suppose they're a little worse than instVarAt:put: and > basicAt:put:, but not so much. These are fundamentally different. #instVarAt:put: and basicAt:put: are regular methods that an object itself implements to give others access to its internal state. It can very well chose not to. > I think it is much more dangerous to > have a debugger that appears to be correct but breaks one's code in > ways that are horribly difficult to understand. > > Note that both Self and Newspeak (and VisualWorks) take the mirror > primitive approach. But there is certainly a security issue and one > wants to medate access to the mirror primitives carefully. Alas we have no way for restricting access in Squeak. Anyway, these primitives are useful for debugging indeed. How about disabling them in production mode? - Bert - |
On Mon, Sep 7, 2009 at 12:34 PM, Bert Freudenberg<[hidden email]> wrote:
> > On 07.09.2009, at 21:29, Eliot Miranda wrote: > >> On Mon, Sep 7, 2009 at 12:19 PM, Bert Freudenberg<[hidden email]> >> wrote: >>> >>> On 07.09.2009, at 20:56, Eliot Miranda wrote: >>>> >>>> I have fixes for this integrated in Qwaq. This is work I did for >>>> VisualWorks a while back. The idea is to add a set of mirror >>>> primitives, so called because they do reflection, to ContextPart. >>>> These primitives implement the basic operations of the object model >>>> needed for execution simulation, fetching an object's class, accessing >>>> its named and indexed instance variables, and the number of indexed >>>> instance variables, sending a message, but they take the object >>>> operated on as a parameter and so do function without sending messages >>>> to that object. >>> >>> Wouldn't that break encapsulation in a way we never had to before? >> >> If one dared use those primitives for anything other than simulating >> the VM then I suppose they're a little worse than instVarAt:put: and >> basicAt:put:, but not so much. > > These are fundamentally different. #instVarAt:put: and basicAt:put: are > regular methods that an object itself implements to give others access to > its internal state. It can very well chose not to. Yes, but they are implemented in Object and potentially defeat encapsulation on every object in the system that inherits from it (which is almost all). In practice this isn't an issue because they are not abused. Its the same with the mirror primitives. So while it appears the sky can fall in a new way it doesn't. > >> I think it is much more dangerous to >> have a debugger that appears to be correct but breaks one's code in >> ways that are horribly difficult to understand. >> >> Note that both Self and Newspeak (and VisualWorks) take the mirror >> primitive approach. But there is certainly a security issue and one >> wants to medate access to the mirror primitives carefully. > > > Alas we have no way for restricting access in Squeak. I can imagine a way using withArgs:evaluate:. Compile the methods, save them in class variables of ContextPart and access them through a checking interface that only allows their execution in the context of the debugger. But I still think this is overkill. What, in Squeak, is to stop one compiling a method on ProtoObject and using it to subvert encapsulation on all objects? Nothing. So the issue of security is not made any worse by the introduction of the mirror primitives, but the debugger is enhanced significantly. So for me they're a clear win. > > Anyway, these primitives are useful for debugging indeed. How about > disabling them in production mode? Alas the process termination code uses execution simulation to terminate suspended processes and that means using the mirror primitives to safely terminate processes. The current non-mirror implementation could conceivably screw up terminating processes executing code on encapsulators. I think a better way is to propose a security mechanism that prevents their abuse. Any ideas? > > - Bert - > > > |
>From VM's perspective , all object are just a state holders, with slots and
determined size(s). In language environment, however, the objects are treated as a black-boxes to which you can send the messages only. The debugger is staying somewhere in the middle, i.e. it should know how to connect these two realms in order to simulate VM-specific behavior when you stepping over the code. So, for the means of debugging i tend to agree that mirror prims will be quite useful. But same as Bert i don't want to see these prims abused by people who bypassing the 'black-box' paradigm by using them, so we ending up with a 'static-type-oriented' C-like programming instead of object oriented one. 2009/9/7 Eliot Miranda <[hidden email]>: > On Mon, Sep 7, 2009 at 12:34 PM, Bert Freudenberg<[hidden email]> wrote: >> >> On 07.09.2009, at 21:29, Eliot Miranda wrote: >> >>> On Mon, Sep 7, 2009 at 12:19 PM, Bert Freudenberg<[hidden email]> >>> wrote: >>>> >>>> On 07.09.2009, at 20:56, Eliot Miranda wrote: >>>>> >>>>> I have fixes for this integrated in Qwaq. This is work I did for >>>>> VisualWorks a while back. The idea is to add a set of mirror >>>>> primitives, so called because they do reflection, to ContextPart. >>>>> These primitives implement the basic operations of the object model >>>>> needed for execution simulation, fetching an object's class, accessing >>>>> its named and indexed instance variables, and the number of indexed >>>>> instance variables, sending a message, but they take the object >>>>> operated on as a parameter and so do function without sending messages >>>>> to that object. >>>> >>>> Wouldn't that break encapsulation in a way we never had to before? >>> >>> If one dared use those primitives for anything other than simulating >>> the VM then I suppose they're a little worse than instVarAt:put: and >>> basicAt:put:, but not so much. >> >> These are fundamentally different. #instVarAt:put: and basicAt:put: are >> regular methods that an object itself implements to give others access to >> its internal state. It can very well chose not to. > > Yes, but they are implemented in Object and potentially defeat > encapsulation on every object in the system that inherits from it > (which is almost all). In practice this isn't an issue because they > are not abused. Its the same with the mirror primitives. So while it > appears the sky can fall in a new way it doesn't. > >> >>> I think it is much more dangerous to >>> have a debugger that appears to be correct but breaks one's code in >>> ways that are horribly difficult to understand. >>> >>> Note that both Self and Newspeak (and VisualWorks) take the mirror >>> primitive approach. But there is certainly a security issue and one >>> wants to medate access to the mirror primitives carefully. >> >> >> Alas we have no way for restricting access in Squeak. > > I can imagine a way using withArgs:evaluate:. Compile the methods, > save them in class variables of ContextPart and access them through a > checking interface that only allows their execution in the context of > the debugger. But I still think this is overkill. What, in Squeak, > is to stop one compiling a method on ProtoObject and using it to > subvert encapsulation on all objects? Nothing. So the issue of > security is not made any worse by the introduction of the mirror > primitives, but the debugger is enhanced significantly. So for me > they're a clear win. > > >> >> Anyway, these primitives are useful for debugging indeed. How about >> disabling them in production mode? > > Alas the process termination code uses execution simulation to > terminate suspended processes and that means using the mirror > primitives to safely terminate processes. The current non-mirror > implementation could conceivably screw up terminating processes > executing code on encapsulators. > > I think a better way is to propose a security mechanism that prevents > their abuse. Any ideas? > >> >> - Bert - >> >> >> > > -- Best regards, Igor Stasenko AKA sig. |
On Mon, Sep 7, 2009 at 1:29 PM, Igor Stasenko<[hidden email]> wrote:
> >From VM's perspective , all object are just a state holders, with slots and > determined size(s). > In language environment, however, the objects are treated as a > black-boxes to which you can > send the messages only. > The debugger is staying somewhere in the middle, i.e. it should know > how to connect these two realms > in order to simulate VM-specific behavior when you stepping over the code. > So, for the means of debugging i tend to agree that mirror prims will > be quite useful. > But same as Bert i don't want to see these prims abused by people who > bypassing the 'black-box' paradigm > by using them, so we ending up with a 'static-type-oriented' C-like > programming instead of object oriented one. I understand, but the argument is a bit further along than that. The question is whether the addition of the mirror primitives makes the situation significantly worse than it is already with the presence of instVarAt:put: primitiveChangeClassTo: become: and the compiler. I can easily subvert any encapsulation by a class that doesn't inherit from Object or ProtoObject and doesn't implement instVarAt:put: by using reflection to enumerate over all classes, and adding the instVarAt:put: method to all root classes' method dictionaries under a selector of my choosing. I can construct a context activation on some object with a method of my construction and set it running. I don't even have to have the compiler for either of these exploits. The open meta system is simply not secure. I argue that therefore adding the mirror primitives does not materially make the situation any worse than it already is, but does give one an accurate debugger, and accurate process termination. I argue that the mirror primitives are in some sense isomorphic in their insecurity to the existing meta facilities (such as open access to thisContext), but that in practice the openness of the meta-system has not presented a security problem; images and processes are still sealed, and secure applications which do not allow the import or execution of arbitrary code can still be deployed even though they contain apparently insecure code because they do not provide a path such that externally that unsafe code can be activated, and because internally those applications do not misuse the encapsulation-violating facilities such as instVarAt:put:. I argue that in practice encapsulation is a design convention that allows one to reason more effectively about complex systems, but that it is not a hard-and-fast rule, and that breaking encapsulation in certain stereotypical situations is common and extremely useful, for example in reconstructing or transporting objects that have been externalised on some stream. > > 2009/9/7 Eliot Miranda <[hidden email]>: >> On Mon, Sep 7, 2009 at 12:34 PM, Bert Freudenberg<[hidden email]> wrote: >>> >>> On 07.09.2009, at 21:29, Eliot Miranda wrote: >>> >>>> On Mon, Sep 7, 2009 at 12:19 PM, Bert Freudenberg<[hidden email]> >>>> wrote: >>>>> >>>>> On 07.09.2009, at 20:56, Eliot Miranda wrote: >>>>>> >>>>>> I have fixes for this integrated in Qwaq. This is work I did for >>>>>> VisualWorks a while back. The idea is to add a set of mirror >>>>>> primitives, so called because they do reflection, to ContextPart. >>>>>> These primitives implement the basic operations of the object model >>>>>> needed for execution simulation, fetching an object's class, accessing >>>>>> its named and indexed instance variables, and the number of indexed >>>>>> instance variables, sending a message, but they take the object >>>>>> operated on as a parameter and so do function without sending messages >>>>>> to that object. >>>>> >>>>> Wouldn't that break encapsulation in a way we never had to before? >>>> >>>> If one dared use those primitives for anything other than simulating >>>> the VM then I suppose they're a little worse than instVarAt:put: and >>>> basicAt:put:, but not so much. >>> >>> These are fundamentally different. #instVarAt:put: and basicAt:put: are >>> regular methods that an object itself implements to give others access to >>> its internal state. It can very well chose not to. >> >> Yes, but they are implemented in Object and potentially defeat >> encapsulation on every object in the system that inherits from it >> (which is almost all). In practice this isn't an issue because they >> are not abused. Its the same with the mirror primitives. So while it >> appears the sky can fall in a new way it doesn't. >> >>> >>>> I think it is much more dangerous to >>>> have a debugger that appears to be correct but breaks one's code in >>>> ways that are horribly difficult to understand. >>>> >>>> Note that both Self and Newspeak (and VisualWorks) take the mirror >>>> primitive approach. But there is certainly a security issue and one >>>> wants to medate access to the mirror primitives carefully. >>> >>> >>> Alas we have no way for restricting access in Squeak. >> >> I can imagine a way using withArgs:evaluate:. Compile the methods, >> save them in class variables of ContextPart and access them through a >> checking interface that only allows their execution in the context of >> the debugger. But I still think this is overkill. What, in Squeak, >> is to stop one compiling a method on ProtoObject and using it to >> subvert encapsulation on all objects? Nothing. So the issue of >> security is not made any worse by the introduction of the mirror >> primitives, but the debugger is enhanced significantly. So for me >> they're a clear win. >> >> >>> >>> Anyway, these primitives are useful for debugging indeed. How about >>> disabling them in production mode? >> >> Alas the process termination code uses execution simulation to >> terminate suspended processes and that means using the mirror >> primitives to safely terminate processes. The current non-mirror >> implementation could conceivably screw up terminating processes >> executing code on encapsulators. >> >> I think a better way is to propose a security mechanism that prevents >> their abuse. Any ideas? >> >>> >>> - Bert - >>> >>> >>> >> >> > > > > -- > Best regards, > Igor Stasenko AKA sig. > > |
In reply to this post by Eliot Miranda-2
On 7-Sep-09, at 1:10 PM, Eliot Miranda wrote: > I can imagine a way using withArgs:evaluate:. Compile the methods, > save them in class variables of ContextPart and access them through a > checking interface that only allows their execution in the context of > the debugger. But I still think this is overkill. What, in Squeak, > is to stop one compiling a method on ProtoObject and using it to > subvert encapsulation on all objects? Nothing. So the issue of > security is not made any worse by the introduction of the mirror > primitives, but the debugger is enhanced significantly. So for me > they're a clear win. One year at StS I had a discussion with Travis about Trippy. He mentioned to me that they had planned to use the mirror primitives for Trippy, but ultimately found that it was better to do something similar to what you describe above: compile a method that answers an instvar then execute with the object as the receiver using the inverse of #withArgs:evaluate: something like #valueWithReciever:args: on CompiledMethod. This seems like a powerful and flexible approach to me. You can do anything the object its self can do with its internal state, but completely bypass message dispatch. Best of all there's only one primitive required. Admittedly a debugger involves a bit more than an inspector, but the technique would seem to be applicable. Is there some reason that this combined with traditional simulation wouldn't work well? Colin |
In reply to this post by Eliot Miranda-2
Eliot Miranda wrote:
> I argue that therefore adding the mirror primitives does not > materially make the situation any worse than it already is, but does > give one an accurate debugger, and accurate process termination. I > argue that the mirror primitives are in some sense isomorphic in their > insecurity to the existing meta facilities (such as open access to > thisContext), but that in practice the openness of the meta-system has > not presented a security problem; images and processes are still > sealed, and secure applications which do not allow the import or > execution of arbitrary code can still be deployed even though they > contain apparently insecure code because they do not provide a path > such that externally that unsafe code can be activated, and because > internally those applications do not misuse the > encapsulation-violating facilities such as instVarAt:put:. Not only agreed but I will go one step further by claiming that if anyone ever tries to build a secure system they will soon find that an absolutely necessary step is to use mirrors for accessing critical object/vm state. Reliance on a correct implementation of #basicAt: is not an option if the objects must be assumed to be hostile. Cheers, - Andreas |
In reply to this post by Colin Putney
On Mon, Sep 7, 2009 at 1:47 PM, Colin Putney<[hidden email]> wrote:
> > On 7-Sep-09, at 1:10 PM, Eliot Miranda wrote: > >> I can imagine a way using withArgs:evaluate:. Compile the methods, >> save them in class variables of ContextPart and access them through a >> checking interface that only allows their execution in the context of >> the debugger. But I still think this is overkill. What, in Squeak, >> is to stop one compiling a method on ProtoObject and using it to >> subvert encapsulation on all objects? Nothing. So the issue of >> security is not made any worse by the introduction of the mirror >> primitives, but the debugger is enhanced significantly. So for me >> they're a clear win. > > One year at StS I had a discussion with Travis about Trippy. He mentioned to > me that they had planned to use the mirror primitives for Trippy, but > ultimately found that it was better to do something similar to what you > describe above: compile a method that answers an instvar then execute with > the object as the receiver using the inverse of #withArgs:evaluate: > something like #valueWithReciever:args: on CompiledMethod. This seems like a > powerful and flexible approach to me. You can do anything the object its > self can do with its internal state, but completely bypass message dispatch. > Best of all there's only one primitive required. In Squeak valueWithReciever:args: is built upon withArgs:evaluate:. See my other posts on the holes that valueWithReciever:args: open up. The VW debugger still uses the mirror primitives so I don't see the engineering effort to add the alternative path was worth it. > Admittedly a debugger involves a bit more than an inspector, but the > technique would seem to be applicable. Is there some reason that this > combined with traditional simulation wouldn't work well? In principle, no. Provided one caches the methods, then there's no performance issue. But is it any better? There's no difference in security. The fact that one can implement things either way demonstrates this. The security issue is whether the system can work correctly without facilities analogous to the mirror primitives. The implementation of Process>>terminate means that there isn't, because it uses the execution simulation machinery, and for correctness the execution simulation machinery needs mechanisms isomorphic to the mirror primitives, no matter how they are implemented. I think an implementation which makes it easy to strip out the mirror primitives when deploying is attractive. The mirror primitives are simple to use and understand. So the thing to focus on is process termination. Remove execution simulation from that path and the system is more secure (if that's important to you). Keep incorrect execution simulation in process termination and the system functions without the mirror primitive hole (but with plenty of others) but is incorrect w.r.t. processes on encapsulators (if that's important to you). > > Colin > > |
In reply to this post by Eliot Miranda-2
Oops. I left out popTo: et al and so Processor activeProcess would be
wrong inside unwind blocks evaluated in the debugger. So find v2 attached... On Mon, Sep 7, 2009 at 12:25 PM, Eliot Miranda<[hidden email]> wrote: > On Mon, Sep 7, 2009 at 11:56 AM, Eliot Miranda<[hidden email]> wrote: >> Hi Igor, >> >> On Mon, Sep 7, 2009 at 10:29 AM, Igor Stasenko <[hidden email]> wrote: >>> >>> 2009/9/7 Bert Freudenberg <[hidden email]>: >>> > >>> > On 07.09.2009, at 18:40, Randal L. Schwartz wrote: >>> > >>> >>>>>>> "Igor" == Igor Stasenko <[hidden email]> writes: >>> >> >>> >> Igor> Here is the default implementation of >>> >> >>> >> Object> debugPrintOn: aStream >>> >> Igor> ^ self printOn: aStream >>> >> >>> >> I like it, but I don't like the name. It conjurs up the idea of debugging >>> >> the #printOn: method itself. >>> >> >>> >> maybe #printForDebuggerOn: ? >>> > >>> > >>> > It matches the other methods like #longPrintOn: though. >>> > >>> > Also that would imply only the debugger invokes it, when it's clearly >>> > appropriate for any purpose. >>> > >>> > However, apart from this bike shedding ;) do others think it's a good idea >>> > in general? IMHO #printOn: is primarily used for debugging anyway so I >>> > wouldn't really expect a separate debug print method to be needed. Debugging >>> > transparent proxies isn't for the faint-of-heart anyway, so these developers >>> > can adapt their tools and proxies I would guess. OTOH there is precedence in >>> > e.g. #asExplorerString, which exists solely to get rid of the quotes >>> > enclosing strings for aesthetic reasons ... >>> > >>> >>> I agree with you Bert, that we should consider if its really necessary. >>> While #printOn: is used by most code for debugging, some of the code >>> using it to serialize object to textual stream, so the #printOn: usage >>> is much more generic than just debugging. >>> >>> As for debugging the transparent proxies - yes you can make own >>> tools.. but this means reimplementing/hacking >>> other tools , like debugger, inspector and so on, which will probably >>> end up with similar solution to what i proposing. >>> >>> For example, there was a point of discrepancy with debugging the code >>> which uses Magma. >>> The magma forwarding proxy reifying the object once the first real >>> message is sent to it. >>> And the problem with such a proxy, that you can't use them in certain >>> situations, like: >>> >>> self perform: aSelectorProxied with: #foo >>> >>> because #perform doesn't sends the messages to aSelectorProxied and >>> primitive fails. But then, when you entering the debugger and trying >>> to figure out why its not working - a proxy becomes a real object when >>> it printed out.. and so you can't debug the error using debugger. >>> Which leaves you to wonder, why code works in debugger, but not >>> working at run time :) >> >> I have fixes for this integrated in Qwaq. This is work I did for >> VisualWorks a while back. The idea is to add a set of mirror >> primitives, so called because they do reflection, to ContextPart. >> These primitives implement the basic operations of the object model >> needed for execution simulation, fetching an object's class, accessing >> its named and indexed instance variables, and the number of indexed >> instance variables, sending a message, but they take the object >> operated on as a parameter and so do function without sending messages >> to that object. These primitives are then used by the execution >> simulation machinery to correctly simulate the execution of the >> virtual machine irrespective of the class and/or messages implemented >> by the receiver. >> >> For example, (eschewing HTML for Bert's contentment) >> >> ContextPart methods for mirror primitives >> object: anObject instVarAt: anIndex >> "Primitive. Answer a fixed variable in an object. The numbering of the >> variables corresponds to the named instance variables. Fail if the index >> is not an Integer or is not the index of a fixed variable. Essential for the >> debugger. See Object documentation whatIsAPrimitive." >> >> <primitive: 73> >> "Access beyond fixed variables." >> ^self object: anObject basicAt: anIndex - (self objectClass: anObject) instSize >> >> object: anObject instVarAt: anIndex put: aValue >> "Primitive. Store a value into a fixed variable in the argument anObject. >> The numbering of the variables corresponds to the named instance >> variables. Fail if the index is not an Integer or is not the index of a >> fixed variable. Answer the value stored as the result. Using this >> message violates the principle that each object has sovereign control >> over the storing of values into its instance variables. Essential for the >> debugger. See Object documentation whatIsAPrimitive." >> >> <primitive: 74> >> "Access beyond fixed fields" >> ^self object: anObject basicAt: anIndex - (self objectClass: >> anObject) instSize put: aValue >> >> ContextPart methods for instruction decoding >> pushReceiverVariable: offset >> "Simulate the action of bytecode that pushes the contents of the receiver's >> instance variable whose index is the argument, index, on the top of the stack." >> >> self push: (self object: self receiver instVarAt: offset + 1) >> >> popIntoReceiverVariable: offset >> "Simulate the action of bytecode that removes the top of the stack and >> stores it into an instance variable of my receiver." >> >> self object: self receiver instVarAt: offset + 1 put: self pop >> >> storeIntoReceiverVariable: offset >> "Simulate the action of bytecode that stores the top of the stack into an >> instance variable of my receiver." >> >> self object: self receiver instVarAt: offset + 1 put: self top >> >> The attached change set for the image level code is also conflated >> with changes that allow the debugger to set the primitive error code >> correctly. >> >> >> The VM also needs to implement the primitives. If the order of the >> arguments are the same as those of the corresponding non-reflective >> primitive (e.g. aContext object: theReceiver instVarAt: index put: >> value has the same order as theReceiver instVarAt: index put: value) >> and the primitive pops back the stack using self pop: argumentCount + >> 1, one can use the same VM primitive implementations as the >> non-reflective ones and so avoid needing extra primitives. >> >> However, not all primitives are correctly implemented; e.g. at: and >> at:put: are, but size is not. So before we can use this there is some >> work to do in the standard VMs. I'm attaching here the implementation >> in the Stack VM which will require some back porting to the standard >> VM. None of these changes has performance implications because the >> special selector impelmentations of at: at:put: size and #== are not >> affected. >> >> With the above changes one can safely step through code that uses >> proxies that do not inherit from Object, or even ProtoObject. I still >> need to implement a PrimitiveObjectInspector, or use the mirror >> primitives in implementing the Inspector. However, there is one more >> important thing needed in the debugger which these changes do not >> address and that is the value of Processor activeProcess within the >> debugger. e.g. "print it" the following: >> >> | thisProcessOutsideTheDebugger thisProcessInsideTheDebugger | >> thisProcessOutsideTheDebugger := Processor activeProcess. >> self halt. >> thisProcessInsideTheDebugger := Processor activeProcess. >> 'Send to here (Into) then proceed'. >> thisProcessOutsideTheDebugger == thisProcessInsideTheDebugger >> >> This will potentially break debugging of servers that maintain process >> pools. Andreas has proposed a very simple fix for this. Add an >> instance variable to Process called, e.g. effectiveProcess, which is >> nil in normal processes. When the debugger runs it sets >> effectiveProcess to that of the process which it is debugging and >> Processor activeProcess is implemented as something like >> >> ProcessorScheduler methods for accessing >> activeProcess >> ^activeProcess effectiveProcess ifNil: [activeProcess] >> >> I'll try and get round to this soon. > > That appeared to be very easy, because the debugger is well-factored, > deferring to its interruptedProcess for all execution. care to bang > on the attached? The definition of process is probably wrong for your > image so integrate that carefully. > > >> >> >> I'm posting this rather than integrating because a) the VMs need to >> get updated before we can use the image level code and, b) the VM >> folks need code to test their VMs with. I'm happy to integrate the >> image-level changes once the VMs have been upgraded. >> >> best >> Eliot >> >>> >>> > >>> > - Bert - >>> > >>> >>> >>> -- >>> Best regards, >>> Igor Stasenko AKA sig. >>> >> > effectiveProcess.st (5K) Download Attachment |
In reply to this post by Eliot Miranda-2
I would just like to mention that Self (and it is likely that Newspeak
too, but I haven't looked) has mirror *objects* and not mirror *primitives*. Yes, these objects actually use primitives to get their work done but these primitives don't work for any objects other than mirrors (and if Self didn't have a global namespace for primitives, this check wouldn't even be necessary since non mirror objects wouldn't even have a way to try to invoke these primitives). The mirror objects operate on only one object that is stored as an "instance variable" when the mirror was created, so you can't pass random objects as parameters. To have a secure system you would only have to control the code that allows new mirrors to be created. Unfortunately, Self didn't do that but instead allows anybody to create a mirror on anybody else. It wouldn't be very hard to do, however. Of course, as has already been pointed out this wouldn't get you much in terms of security if you keep all the current holes that Squeak has. One possible objection to mirror objects is that you might need to create them exactly in situations where creating new objects might cause problems (low memory or certain kinds of bugs). http://bracha.org/mirrors.pdf has good background information for anybody having problems keeping up with this thread. -- Jecel |
In reply to this post by Eliot Miranda-2
2009/9/7 Jecel Assumpcao Jr <[hidden email]>:
> I would just like to mention that Self (and it is likely that Newspeak > too, but I haven't looked) has mirror *objects* and not mirror > *primitives*. Yes, these objects actually use primitives to get their > work done but these primitives don't work for any objects other than > mirrors (and if Self didn't have a global namespace for primitives, this > check wouldn't even be necessary since non mirror objects wouldn't even > have a way to try to invoke these primitives). > is this means that mirror primitive implemented to look at some slot of the receiver object instead of taking a message argument to reflect the properties of object to be mirrored? If so, then it is better, because it makes a bit harder to abuse the prims. > The mirror objects operate on only one object that is stored as an > "instance variable" when the mirror was created, so you can't pass > random objects as parameters. To have a secure system you would only > have to control the code that allows new mirrors to be created. > Unfortunately, Self didn't do that but instead allows anybody to create > a mirror on anybody else. It wouldn't be very hard to do, however. Of > course, as has already been pointed out this wouldn't get you much in > terms of security if you keep all the current holes that Squeak has. > If we will go at some point to make a secure system, then we should care at least to not add a new security gaps and holes in addition to what we already having - means less work for people who would want to make a secure system (like Mike van der Gulik) > One possible objection to mirror objects is that you might need to > create them exactly in situations where creating new objects might cause > problems (low memory or certain kinds of bugs). > > http://bracha.org/mirrors.pdf has good background information for > anybody having problems keeping up with this thread. > > -- Jecel > -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Eliot Miranda-2
Eliot (phone) On 7 Sep 2009, at 14:35, "Jecel Assumpcao Jr" <[hidden email]> wrote: > I would just like to mention that Self (and it is likely that Newspeak > too, but I haven't looked) has mirror *objects* and not mirror > *primitives*. Yes, these objects actually use primitives to get their > work done but these primitives don't work for any objects other than > mirrors (and if Self didn't have a global namespace for primitives, > this > check wouldn't even be necessary since non mirror objects wouldn't > even > have a way to try to invoke these primitives). > > The mirror objects operate on only one object that is stored as an > "instance variable" when the mirror was created, so you can't pass > random objects as parameters. To have a secure system you would only > have to control the code that allows new mirrors to be created. > Unfortunately, Self didn't do that but instead allows anybody to > create > a mirror on anybody else. It wouldn't be very hard to do, however. Of > course, as has already been pointed out this wouldn't get you much in > terms of security if you keep all the current holes that Squeak has. > Ok, that presents a straight-forward e xtension to the primitive implementations (forgive typoes; I'm at the park + kids). If the argument count is higher than the base primitive's we insist on the receiver being a context who's receiver is the object to be acted upon, e.g. primitiveInstVarAt (argumentCount > 2 and: [(self isIntegerObject: (self stackValue: argumentCount)) or: [(self isContext: (self stackValue: argumentCount)) not or: [(self fetchPointer: ReceiverIndex ofObject: (self stackValue: argumentCount)) ~= (self stackValue: 2)]]]]) ifTrue: [^self primitiveFail]. .... then the mirror primitives are safe. Yes? > One possible objection to mirror objects is that you might need to > create them exactly in situations where creating new objects might > cause > problems (low memory or certain kinds of bugs). > > http://bracha.org/mirrors.pdf has good background information for > anybody having problems keeping up with this thread. > > -- Jecel > > |
In reply to this post by Igor Stasenko
Thinking a bit about mirrors , i found that they could be useful for
debugging/inspecting purposes without actually exposing the referenced object contents to sender i.e. instead of: (objectOrMirroredObject instVarAt: i) printOn: aStream provide it in a form: objectOrMirroredObject printInstVarAt: i on: aStream -- Best regards, Igor Stasenko AKA sig. |
In reply to this post by Eliot Miranda-2
2009/9/7 Eliot Miranda <[hidden email]>:
> > > Eliot (phone) > > On 7 Sep 2009, at 14:35, "Jecel Assumpcao Jr" <[hidden email]> wrote: > >> I would just like to mention that Self (and it is likely that Newspeak >> too, but I haven't looked) has mirror *objects* and not mirror >> *primitives*. Yes, these objects actually use primitives to get their >> work done but these primitives don't work for any objects other than >> mirrors (and if Self didn't have a global namespace for primitives, this >> check wouldn't even be necessary since non mirror objects wouldn't even >> have a way to try to invoke these primitives). >> >> The mirror objects operate on only one object that is stored as an >> "instance variable" when the mirror was created, so you can't pass >> random objects as parameters. To have a secure system you would only >> have to control the code that allows new mirrors to be created. >> Unfortunately, Self didn't do that but instead allows anybody to create >> a mirror on anybody else. It wouldn't be very hard to do, however. Of >> course, as has already been pointed out this wouldn't get you much in >> terms of security if you keep all the current holes that Squeak has. >> > > Ok, that presents a straight-forward e xtension to the primitive > implementations (forgive typoes; I'm at the park + kids). If the argument > count is higher than the base primitive's we insist on the receiver being a > context who's receiver is the object to be acted upon, e.g. > > primitiveInstVarAt > (argumentCount > 2 > and: [(self isIntegerObject: (self stackValue: argumentCount)) > or: [(self isContext: (self stackValue: argumentCount)) not > or: [(self fetchPointer: ReceiverIndex ofObject: (self > stackValue: argumentCount)) ~= (self stackValue: 2)]]]]) ifTrue: > [^self primitiveFail]. > > .... > > then the mirror primitives are safe. > > Yes? > sorry, can't follow.. its hard to grok through the slang code, even if its a smalltalk. Can you please provide the analogous simplified implementation in non-slang code which will show the actual intent of safety checks? > > >> One possible objection to mirror objects is that you might need to >> create them exactly in situations where creating new objects might cause >> problems (low memory or certain kinds of bugs). >> >> http://bracha.org/mirrors.pdf has good background information for >> anybody having problems keeping up with this thread. >> >> -- Jecel >> >> > > -- Best regards, Igor Stasenko AKA sig. |
On Mon, Sep 7, 2009 at 5:36 PM, Igor Stasenko<[hidden email]> wrote:
> 2009/9/7 Eliot Miranda <[hidden email]>: >> >> >> Eliot (phone) >> >> On 7 Sep 2009, at 14:35, "Jecel Assumpcao Jr" <[hidden email]> wrote: >> >>> I would just like to mention that Self (and it is likely that Newspeak >>> too, but I haven't looked) has mirror *objects* and not mirror >>> *primitives*. Yes, these objects actually use primitives to get their >>> work done but these primitives don't work for any objects other than >>> mirrors (and if Self didn't have a global namespace for primitives, this >>> check wouldn't even be necessary since non mirror objects wouldn't even >>> have a way to try to invoke these primitives). >>> >>> The mirror objects operate on only one object that is stored as an >>> "instance variable" when the mirror was created, so you can't pass >>> random objects as parameters. To have a secure system you would only >>> have to control the code that allows new mirrors to be created. >>> Unfortunately, Self didn't do that but instead allows anybody to create >>> a mirror on anybody else. It wouldn't be very hard to do, however. Of >>> course, as has already been pointed out this wouldn't get you much in >>> terms of security if you keep all the current holes that Squeak has. >>> >> >> Ok, that presents a straight-forward e xtension to the primitive >> implementations (forgive typoes; I'm at the park + kids). If the argument >> count is higher than the base primitive's we insist on the receiver being a >> context who's receiver is the object to be acted upon, e.g. >> >> primitiveInstVarAt >> (argumentCount > 2 >> and: [(self isIntegerObject: (self stackValue: argumentCount)) >> or: [(self isContext: (self stackValue: argumentCount)) not >> or: [(self fetchPointer: ReceiverIndex ofObject: (self >> stackValue: argumentCount)) ~= (self stackValue: 2)]]]]) ifTrue: >> [^self primitiveFail]. >> >> .... >> >> then the mirror primitives are safe. >> >> Yes? >> > > sorry, can't follow.. its hard to grok through the slang code, even if > its a smalltalk. > Can you please provide the analogous simplified implementation in > non-slang code which will show the actual intent of safety checks? primitiveInstVarAt argumentCount > 2 ifTrue:"if so this is a mirror prim" [ | receiver objectToFetchInstVarFrom | receiver := self stackValue: argumentCount. objectToFetchInstVarFrom := self stackValue: 2. (receiver isContext not or: [receiver receiver ~= objectToFetchInstVarFrom]) ifTrue: [^self primitiveFail]]. ... go fetch the inst var ... > >> >> >>> One possible objection to mirror objects is that you might need to >>> create them exactly in situations where creating new objects might cause >>> problems (low memory or certain kinds of bugs). >>> >>> http://bracha.org/mirrors.pdf has good background information for >>> anybody having problems keeping up with this thread. >>> >>> -- Jecel >>> >>> >> >> > > > > -- > Best regards, > Igor Stasenko AKA sig. > > |
In reply to this post by Eliot Miranda-2
Instead of implementing #activeProcess as
activeProcess ^activeProcess effectiveProcess ifNil: [activeProcess] Why not have the effectiveProcess ivar point to the receiver unless debugging is in process. Then #activeProcess would be activeProcess ^activeProcess effectiveProcess and effectiveProcess would be effectiveProcess ^effectiveProcess Terry =========================================================== Terry Raymond Crafted Smalltalk 80 Lazywood Ln. Tiverton, RI 02878 (401) 624-4517 [hidden email] <http://www.craftedsmalltalk.com> =========================================================== |
On Tue, Sep 8, 2009 at 6:20 AM, Terry Raymond<[hidden email]> wrote:
> Instead of implementing #activeProcess as > > activeProcess > ^activeProcess effectiveProcess ifNil: [activeProcess] > > Why not have the effectiveProcess ivar point to the receiver > unless debugging is in process. Then #activeProcess would be > > activeProcess > ^activeProcess effectiveProcess > > and effectiveProcess would be > > effectiveProcess > ^effectiveProcess In the end I put the check in Process>>effectiveProcess. I don't want to have to guarantee that effectiveProcess gets assigned on Process creation. There isn't an existing Process>>initialize method so I didn't want to add overhead or tax a ref counting GC etc, etc. So I ended up with what you have above except for effectiveProcess ^effectiveProcess ifNil: [self] > > > Terry > > =========================================================== > Terry Raymond > Crafted Smalltalk > 80 Lazywood Ln. > Tiverton, RI 02878 > (401) 624-4517 [hidden email] > <http://www.craftedsmalltalk.com> > =========================================================== > > > |
Free forum by Nabble | Edit this page |