Private data

Dustan DustanGroups at gmail.com
Sun Mar 18 09:29:00 EDT 2007


On Mar 18, 8:21 am, "Dustan" <DustanGro... at gmail.com> wrote:
> On Mar 18, 7:25 am, "Dustan" <DustanGro... at gmail.com> wrote:
>
>
>
> > On Mar 18, 7:06 am, Steven D'Aprano
> > > First, an example of the code in action.
>
> > > >>> import PrivateAttributes
> > > >>> obj = PrivateAttributes.TestPrivateClassAttributes()
> > > >>> obj.getNumInstances()
> > > 1
> > > >>> another = PrivateAttributes.TestPrivateClassAttributes()
> > > >>> obj.getNumInstances()
> > > 2
> > > >>> athird = PrivateAttributes.TestPrivateClassAttributes()
> > > >>> athird.getNumInstances()
>
> > > 3
>
> > > The getNumInstances method reports the number of instances of the
> > > PrivateAttributes class. There's no obvious class attribute where this
> > > count is being kept:
>
> > > >>> obj.__class__.__dict__.keys()
>
> > > ['__module__', 'getNumInstances', '__dict__', '__weakref__', '__doc__',
> > > '__init__']
>
> > > Here's how to hack it, and make it report wrong numbers.
>
> > > >>> c = obj.getNumInstances.func_closure
> > > >>> c[1].cell_contents.numInstances = -300
>
> > > >>> athird.getNumInstances()
> > > -300
> > > >>> afourth = PrivateAttributes.TestPrivateClassAttributes()
> > > >>> athird.getNumInstances()
>
> > > -299
>
> > > So yes, it is absolutely hackable.
>
> > I did have a feeling that it was hackable, but had no idea how one
> > could possibly go about hacking it (I was starting to wonder of there
> > was a way to apply locals() and globals() on functions). But now I
> > (ehem) sorta know how it's done.
>
> > > Now, I'm hardly a Python guru, but in about fifteen minutes I followed the
> > > trail through the object chain, and found how to hack this. An real guru
> > > would probably do it in three minutes.
>
> > > I was helped a bit by having the source code. But even without the source
> > > code, I reckon I could have done it in an hour or so, if I was motivated
> > > enough. All the tools you need are a Python interactive session, the dir()
> > > function and the dis module.
>
> > I have used all of those before, but I haven't been able to fully
> > understand the output of the dis module; maybe that's my problem.
>
> Alright, perhaps you can help me out with this learning curve here. I
> have seen, but not worked with, some basic assembly code, so I think I
> have a vague idea of what it all means, although I have a feeling it's
> not all valid assembly (on any widely used machine).
>
> First I dis.dis'd testPrivateStaticFunctionVariables:
>
> >>> dis.dis(testPrivateStaticFunctionVariables)
>
>  21           0 LOAD_DEREF               0 (func)
>               3 LOAD_DEREF               1 (internalData)
>               6 LOAD_FAST                0 (args)
>               9 CALL_FUNCTION_VAR        1
>              12 RETURN_VALUE
>
> At first I was a little confused by this, because there's no increment
> in sight, but then I realized it was dis.dis'ing the wrapper closure
> in the internalDataDecorator closure in the PrivateDataEngine function
> (and then I hit myself on the head and cried out "doh!"). So that
> 'code' is coming from this (taken out of closure):
>
> def wrapper(*args):
>     return func(internalData, *args)
>
> So, based on what you showed me, I found my way after some failed
> tries to this:
>
> >>> dis.dis(testPrivateStaticFunctionVariables.func_closure[0].cell_contents)
>
>  28           0 LOAD_FAST                0 (internalData)
>               3 DUP_TOP
>               4 LOAD_ATTR                0 (numCalls)
>               7 LOAD_CONST               1 (1)
>              10 INPLACE_ADD
>              11 ROT_TWO
>              12 STORE_ATTR               0 (numCalls)
>
>  29          15 LOAD_FAST                0 (internalData)
>              18 LOAD_ATTR                0 (numCalls)
>              21 RETURN_VALUE
>
> That's coming from this:
>
> @PrivateDataEngine(numCalls = 0)
> def testPrivateStaticFunctionVariables(internalData):
>     """returns the number of times this function has been called."""
>     internalData.numCalls += 1
>     return internalData.numCalls
>
> Here's a few questions on this output, for which I would highly
> appreciate some answers:
>
> What's the difference between 'LOAD_DEREF', 'LOAD_FAST', and
> 'LOAD_CONST', and, as seen athttp://docs.python.org/lib/module-dis.html,
> 'LOAD_GLOBAL'? I can imagine that 'LOAD_GLOBAL' loads a global, but
> seeing as python is such a dynamic language, how exactly is it
> supposed to distinguish between them?
>
> I don't understand the following at all: 'DUP_TOP', 'ROT_TWO'. Any
> pointers?
>
> What does 'INPLACE_ADD' mean, if not in place addition, and if it is
> in place addition, why does it need to 'STORE_ATTR' afterward?
>
> Thanks for any help!

If this had been on any other usenet group, someone would have RTFM'd
me to hell.
http://docs.python.org/lib/bytecodes.html
I might still have some more questions later, but for now, I'll look
at this.

> > > --
> > > Steven





More information about the Python-list mailing list