4
>> def spam():
...   print("top secret function")
... 
>>> print(spam)
<function spam at 0x7feccc97fb78>
>>> spam = "spam"

So I lose the reference to spam function. Can I get it back from that memory address: 0x7feccc97fb78?

>>> orig_spam_function = get_orig_func_from_memory_address("0x7feccc97fb78")

Edit (responding to thefourtheye):

Sorry for the lousy question, consider this case:

>>> from collections import defaultdict
>>> d = defaultdict(spam)
>>> d
defaultdict(<function spam at 0x7f597572c270>, {})

So the function is not garbaged collected yet. Can I recover it? Of course, in this case, you can use default_factory attribute.

>>> d.default_factory
<function spam at 0x7f597572c270>

But imagine defaultdict without default_factory attribute.

3 Answers 3

3

@thefourtheye raises a good point about the function being garbage-collected.

But if by any chance the function is not garbage-collected, you can look for it in all the existing objects:

def spam():
    pass

spam2 = spam  # keep a reference
print spam
=> <function spam at 0x56d69b0>

import gc
[ obj for obj in gc.get_objects() if id(obj) == 0x56d69b0 ]
=> [<function __main__.spam>]

This is not an efficient way (scans through all the objects in memory), but it is a way.

Sign up to request clarification or add additional context in comments.

2 Comments

If we keep a reference we always can get it back :) Try the same by reassigning with something else
@thefourtheye it's not hard to come up with examples where that isn't the case. like cases where a reference is kept by someone (e.g. another module), but it's not necessarily easy to figure out who that someone is
3

When you assign

spam = "spam"

the last reference to the spam function is gone, the reference count becomes 0 and that will be garbage collected later. So, there is no way, we can get it back. We can check that with this program

def spam():
    print("top secret function")
import sys
print id(spam), sys.getrefcount(spam)
spam = "spam"
print id(spam), sys.getrefcount(spam)

Output on my machine

140068817052928 2
140068817075440 12

The actual address of spam was different than the one which we see after the assignment statement. So, it is pointing to a different object now. But, originally, the reference count is 1 (getrefcount will always be one higher than the actual count). When we reassign spam, now no one is actually pointing to that function. So, it will be ready for garbage collection.

3 Comments

Theoretically you could try to hack up some native code to try to recover it. But there's no guarantee that that address will still have the meaning of a function at the time that your native code gets executed.
Hi, thx for the quick reply. What if the function is not garbaged collected yet? I updated my question.
@vajrasky: CPython uses reference counting; at 0 it is gone. There is no separate GC run to reap it, the GC only serves to break circular references.
0

From a forensics point of view, you probably could if you were to freeze execution directly after the assignment operation and then inspect that location in memory, (obv knowing how to dissect python memory structure) if you were careful you might be able to climb your way back up to some op code instructions, and from those you could probably rewrite the function or something similar by hand.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.