Last Comment Bug 65683 - Function objects should have a caller property
: Function objects should have a caller property
Status: RESOLVED FIXED
: js1.5
Product: Core
Classification: Components
Component: JavaScript Engine (show other bugs)
: Trunk
: x86 All
: P1 enhancement (vote)
: mozilla0.9
Assigned To: Brendan Eich [:brendan]
: Phil Schwartau
Mentors:
http://www.pbwizard.com/class_inherit...
: 68557 (view as bug list)
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2001-01-16 18:03 PST by Jeff Yates
Modified: 2008-10-17 07:48 PDT (History)
7 users (show)
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments
proposed fix, try it out! (1.98 KB, patch)
2001-02-13 02:09 PST, Brendan Eich [:brendan]
no flags Details | Diff | Splinter Review
Testcase for function.caller (794 bytes, text/html)
2001-02-13 11:31 PST, bht237
no flags Details

Description Jeff Yates 2001-01-16 18:03:13 PST
When in a function context (the running code inside a function body) there
should be a method of determining the function that called the currently running
function.  JScript has this as the caller property of the funciton.

For an example see the article at:
http://www.pbwizard.com/class_inheritance.htm#Section6a

This section of the article describes the code above it.  In this article I am
using the caller property as a security measure to make sure that a specific
function modifies an object ONLY if the constructor calls it.  This security
feature does not work in Mozilla because it does not have this property to check.

Jeff.
Comment 1 Phil Schwartau 2001-01-16 19:57:14 PST
cc'ing Brendan on this one - 
Comment 2 Brendan Eich [:brendan] 2001-01-17 01:03:37 PST
All traces of a caller property were removed a while ago, to follow ECMA-262 and
to avoid any chance of a security exploit.  The removal seems to me to have been
overzealous, because it axed the caller property of function objects *and* the
much-more-exploitable caller (or __caller__) property of activation objects.

Confirming, we should consider restoring the caller property of function objects
for old time's sake (JScript imitated it faithfully in cloning JS1.1, where it
originated).  Norris, what do you say?

/be
Comment 3 Norris Boyd 2001-01-17 09:57:47 PST
The purpose of removing the caller and __caller__ was to prevent access from 
untrusted scripts to empowered scripts running from chrome. How is caller any
less dangerous than __caller__? 

Comment 4 Jeff Yates 2001-01-17 10:18:34 PST
Norris, I do not know what "running from chrome" is, but I do not see how
knowing what function called the function currently being executed is a security
risk?  With the advent of DOM in the current browser it is easy now to not only
read the text of another script, but to modify it as well, from within script.

Jeff.
Comment 5 Brendan Eich [:brendan] 2001-01-17 16:45:21 PST
Function objects had a caller property whose value was the *function object*
that last called the first function.  Not the activation object (Call object),
which was what __caller__ (without qualification) would get you when referenced
in an active function's body.  Backtracing the stack requires the latter, and we
judged it too risky even with access checks.  Just finding the function that
called the current function is less scary.

Consider

function f(){g()}
function g(){h()}
function h(){print(h.caller+'###'+h.caller.caller+'###'+h.caller.caller.caller)}
f()

The output should be "\nfunction g() {\n    h();\n}\n\n###\nfunction f() {\n   
g();\n}\n\n###null" or something like that.

If f calls g calls h calls f again, the caller property will link a cyclic list.
Scripts that traverse this list need to check for cycles.  This is how the
caller property of function objects worked in JS in Nav 4.x and 3.x, and it's
what MSIE JScript cloned.

/be
Comment 6 Norris Boyd 2001-01-17 17:30:02 PST
Our worry with __caller__ at least is that a malicious script could look up the 
caller stack and gain access to powerful functions that wouldn't be protected
from calls. Is this not the case with caller as well? 

If my JavaScript function f is called back from chrome, couldn't I use
f.caller to discover my all-powerful caller and potentially invoke it or
access properties of it (like __parent__) that would expose dangerous powers?
Comment 7 Jeff Yates 2001-01-17 18:17:13 PST
I may be butting in, but...here I go anyway.

"If my JavaScript function f is called back from chrome...", is this chrome you
are refering to part of the browser (not script code).  If so, you can always
have the caller property always null if it is called from non-script code.  I do
not think that a script knowing what function called it is too dangerous because
it if a javascript programmer starts calling that function, he will most likely
end up in an infinite loop and run out of stack space.

Jeff.
Comment 8 Brendan Eich [:brendan] 2001-02-06 13:57:34 PST
Norris wrote:
>If my JavaScript function f is called back from chrome, couldn't I use
>f.caller to discover my all-powerful caller and potentially invoke it or
>access properties of it (like __parent__) that would expose dangerous powers?

Not without a hole in our existing subject/object (script principals vs. object
principals) based access checks.  But I recollect that we were not so confident
that we didn't need "defense in depth" here.

/be
Comment 9 Brendan Eich [:brendan] 2001-02-11 22:54:07 PST
*** Bug 68557 has been marked as a duplicate of this bug. ***
Comment 10 bht237 2001-02-13 01:22:51 PST
I respectfully agree with all points Brendan is making in his comments in the
duplicate bug 68557 and try to reconcile the information in here.

Below a revised extract copied from that bug:

Mozilla needs:

1) To be equal in performance with version 4 browsers
1.1) basic window.onerror: see bug 52120
1.2) funcion.caller (without warnings in strict mode, please): This bug

2) To be ahead of the rest and future proof
2.1) window.onerror column number 4th parameter: See bug 67645

With 1) and 2) implemented, Mozilla will hit the 100% mark and I wouldn't know
what else to ask for. But less than 100% in error handling is pretty useless IMHO.

Re: Brendan in bug 68557: "to write defensive JS without either onerror or
try/catch -- what changed?" I must say: IMHO Nothing changed, in fact I have had
to use an error handler offensively only 2 times:
1) when trying to instantiate MS audio engines (unlike Netscape, MS does not
have a plugins array to test what is available) and
2) when trying to open new windows where MSIE often prematurely returns handles
of broken objects. Nothing changed because MSIE has always been that way: Too bad.

Brendan has focused me back right to the point (function.caller):
I think we need a fully-featured, robust error handler to fix genuine human
programming (design) errors and to find browser bug workarounds, not as
_replacement_ of good programming practice.

In the context of re-usable code, please consider this trivial real-life example:
function writeDocumentIntoWindow(windowVar,writeString){//line 1
    var d=windowVar.document;//line 2
    d.open("text/html","replace");
    d.write(s);
    d.close();
}

If an error occurs within this function (usually a security violation on line
2), then window.onerror will not give us enough information to find the real
culprit.
The function itself is error-free but it is still incapable of handling the error.
A functional window.onerror will report that an error occurred on line 2. SO
WHAT????

BUT: With function.caller we can find the culprit (caller who knows how many
levels away) recursively (stack trace).
Although trivial by today's standards, this is HUGHE value and we can create
systems of satisfactory robustness by eliminating programming errors within a
few minutes after they occur.

function.caller is a de facto standard today and Mozilla will look bad if it
doesn't implement it. It does not look very efficient to write try/catch in
every javascript: URL and every JavaScript event including onMouseOver just to
get bugs sorted out (besides the fact that it would not be possible because of
MSIE compatibility problems). 
Comment 11 Brendan Eich [:brendan] 2001-02-13 02:09:31 PST
Created attachment 25145 [details] [diff] [review]
proposed fix, try it out!
Comment 12 bht237 2001-02-13 09:32:02 PST
Brendan, this is extremely exciting, overwhelming! True Open Source
_Development_, not just Open Source.
I am eager to see the change but (my apologies) I suppose I have to wait because
I haven't even taken a beginner's course in C++ and Mozilla source compiling
(probably the next thing I want to do when I get the time). Many thanks!
Comment 13 bht237 2001-02-13 11:31:09 PST
Created attachment 25169 [details]
Testcase for function.caller
Comment 14 Brendan Eich [:brendan] 2001-02-13 15:36:34 PST
Roger, can you r= this?  I'll take it off your hands.

/be
Comment 15 rogerl (gone) 2001-02-14 11:41:23 PST
cool, r=rogerl
Comment 16 John Bandhauer 2001-02-14 13:59:02 PST
sr=jband
Comment 17 Brendan Eich [:brendan] 2001-02-14 14:33:45 PST
bht: your testcase works like a champ.

my patch attached here had tabs (revived via cvs -j from an old jsfun.c
revision).  I'm checking in a tab-free jsfun.c.  Thanks all.

/be
Comment 18 bht237 2001-02-14 18:21:09 PST
Very exciting indeed. Please let me give my hopefully not too off-topic comments.

This was the last defect type of bug that concered me in Mozilla - I think all
others are also in the process of being resolved quickly. Thanks for that.

Mozilla runs without major problems through our very complex JavaScript sites
and it is fun to watch the recent performance improvements.
Mozilla will - hopefully soon - rule the browser world again.

Brendan, if you don't mind looking at what would IMHO increase the perceived
speed of Mozilla, please consider bug 24684 for a moment. I think it would
generate a high reward (not seen in any other browser yet) for very little effort.
At the moment it doesn't look like getting anywhere :(
Comment 19 John Middlemas 2008-10-16 11:59:44 PDT
Shouldn't .caller also work in an error handler? It
doesn't in Mozilla but used to with Netscape 4.7x like this:-

window.onerror=myErrors

function test() {
   nosuchfunction()
}

function myErrors(msg, url, line) {
alert(myErrors.caller.toString())
}

Running test() triggers an error but the alert shows null rather than the
test() function listing as would be expected. This means .caller doesn't work for all functions and you can't construct a caller history (.caller.caller.caller etc) which is exactly the sort of thing you want to do in an error handler.

It is as if triggering onerror cause .caller to be wiped out, whereas .caller
work fine in normal function usage due to this fix.

This point also made in bug 355430.
Comment 20 Brendan Eich [:brendan] 2008-10-16 15:47:50 PDT
John: resolved bugs are no place to put comments -- they'll just be lost if not ignored.

Netscape 4.7x was a long, looong time ago. It did not have exceptions (try/catch) as specified by ES3. Adding those changed how onerror runs -- it runs after the uncaught exception has propagated out of the test function. This is not going to be changed.

Best bet for stack tracing and other debugging/metaprogramming extensions is to raise concrete, well-thought-out proposals in es-discuss@mozilla.org. We've had such discussions already, and caller has been decisively shot down -- it won't be showing up in a future Ecma standard.

See Dave Herman's proposal for ES4, already cut before ES4 was shelved to create Harmony:

http://wiki.ecmascript.org/doku.php?id=proposals:stack_inspection

for one such proposal.

/be
Comment 21 John Middlemas 2008-10-17 07:48:07 PDT
Thanks for clarifying that .caller will not be available in an onerror handler.

I lost quite some time trying to find this out. Was it my error, was it a bug, or intentional, or what. A web search didn't reveal much except that other people were asking the same question and one forum comment did say it was not possible. So I do think it worth commenting here since it is directly relevant to this topic and other people searching in bugzilla can at least find a definitive answer.

Note You need to log in before you can comment on or make changes to this bug.