1

The following seems to be a reasonable use of __caller__:

var foo=1;
function a() {
    var foo=2;
    function b() {
        var foo=3;
        foo; // 3
        this.foo; // 1, from global
        __caller__.foo // 2
    }
    b();
}
a(); // creates a's execution context

However, __caller__ is not available. Why not? If the global context/variable object can be accessed using this, then why not a's?

mk.
  • 11,360
  • 6
  • 40
  • 54

3 Answers3

4

Doc says:

The special property __caller__, which returned the activation object of the caller thus allowing to reconstruct the stack, was removed for security reasons.

And it is easy to see why this could be a security disaster in a browser where much of the UI is implemented in JavaScript. Imagine having one of your functions called by an add-on or other chrome. You could look up the call stack and read callers' (potentially sensitive) variables, or even inject JavaScript values into caller functions, potentially subverting them to do something against the user's wishes. Effectively every web page would get chrome security privileges and completely compromise the browser.

You certainly should never have used it in real JavaScript, because it was a non-standard Mozilla-only implementation detail, not to mention incredibly ugly. It does not have the lexical behaviour you normally expect of JS.

bobince
  • 528,062
  • 107
  • 651
  • 834
  • I can't access the global context of the browser itself using `this`. The security flaw you describe seemed easily addressed by never setting `__caller__` on global scope, thus never providing a reference to privileged code. So I don't see a problem, which leads me to ask this question. – mk. Jan 25 '10 at 17:51
  • You've got lexical scopes and the call stack confused. `__caller__` would step back through the call stack; it needn't ever reach an activation object corresponding to global scope. – bobince Jan 25 '10 at 18:40
  • My bad. "...by never setting it when it provides a ref to privileged code". It's not quite a security disaster if sandboxing it is trivially easy. Or is it for some reason non-trivial? – mk. Jan 26 '10 at 02:40
  • For one case between chrome and non-chrome it might be achievable, but it scuppers the possibility of ever having another security boundary in JavaScript code. According to bug https://bugzilla.mozilla.org/show_bug.cgi?id=65683, “we judged it too risky even with access checks”. This all happened back in the pre-Firefox days. Incidentally in ECMAScript Fifth Edition ‘strict mode’ even `arguments.caller` is gone; it is generally considered that this feature has no legitimate use in code other than a debugger — and Firebug gives us a better way of doing that now. – bobince Jan 26 '10 at 11:13
  • 2
    There's another reason to nix `__caller__`, as the mention on the list at https://mail.mozilla.org/pipermail/es-discuss/2008-September.txt describes: having the property means you have to make a real activation object for every function execution available, just in case a future function suddenly decides it wants to look up the stack. This severely limits the performance optimisations you can do with local variables. – bobince Jan 26 '10 at 11:15
1

I am not really familiar with the subject, but have you tried arguments.callee.caller?

See here: Javascript how do you find the caller function?

Community
  • 1
  • 1
Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • Add `a.baz=99` right above `a();`. Now if we try `arguments.callee.caller.baz` within b(), we'll get 99. Great - let's use `arguments.callee.caller.foo`! We get undefined. Shoot - well, what happened is that `caller` refers to the function *object*, while `__caller__` refers to the variable object (which `foo`=2 gets attached to). – mk. Jan 25 '10 at 16:47
0

In your example, you can argue that things in b should be able to address things in the active instance of a, and it seems reasonable because a encloses b. But if that weren't the case, say you define

    function c() {
        var foo='hedgehog';
        b();
    }

that's something else entirely, so your argument looks like it applies to a pretty special case.

keturn
  • 4,780
  • 3
  • 29
  • 40
  • Special cases are fun and help with understanding. (If your c is in global scope, then its `b` is undefined. If it's within b, then I probably intend to do that - I might be defining a weird recursive function where I need to check the values from the last recurse. Or I may want to pick which scope I define a variable into. Or print a stack trace.) – mk. Jan 25 '10 at 17:12