RobG wrote:
Following is a Brendan Eich comment on Mozilla 0.9 (2001-01-10):
"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)."
I suppose that for a recursive function, each recursion has the same
function object but different activation object. If you could reference
the activation object, then you could climb any stack. But Brendan's
comment says that support for __caller__ was removed long ago.
So I'm really wondering whether I'm missing an angle on this, cause I
just don't see the rationale. It's does not seem to be a security
issue because arguments.callee.caller of the first call into the
recursive function can reach out to its caller.
I think getting a reference to the activation object was seen as a
potential security exploit, hence caller was reinstated but not __caller__.
A year or so ago I was writing a similar caller chain tracing program
but for another purpose (to get the literal name of the instance). Some
discrepancies and bizarrities I had to bypass for that how have some
explanation grace to Rob.
Given a function f(), "arguments" object with all its properties is
created not for the function f() itself, but for the given
instance/heap of the function f() - that is what confusingly reffered
in ECMAScript as Activation object.
I would stay with the "heap" term here because "instance" implies wrong
analogies with the higher level mechanics, while here it is merely a
lower level execution stack mechanics.
There can be multiple heaps created by the same function existing at
once, each with its own argument object. In this heap arguments.caller
either blocked or looped to the "creator" (function f). Otherwise
indeed one could penetrate right into execution stack using caller as
starting point with all possible security problems.
It is interesting to notice that in this concerne:
function f() {
f.caller != arguments.caller;
}
f.caller refers to the function forced function f to create the current
heap. It is really should be explained better than I did - and
definitely better than it's done in ECMA Books.
Some code:
<html>
<head>
<title>callee, caller and stuff...</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<style type="text/css">
body {
margin: 0px 0px;
padding: 10px 10px;
color: #000000;
background-color: #FFFFFF}
</style>
<script type="text/javascript">
var output = null;
function init() {
output = document.forms['frm01'].elements['output'];
}
window.onload = init;
function test1(caller) {
var out = 'Function in intrinsic event handler:\n\n'
out+= (caller)? caller : 'undefined';
output.value = out;
}
function test2(caller) {
var out = 'test2(): function reference behavior:\n\n'
out+= 'arguments.callee = ' + arguments.callee + '\n\n';
out+= 'test2.toString() = ' + test2.toString();
output.value = out;
}
function test3() {
var out = 'arguments.caller = ' + arguments.caller + '\n\n';
out+= 'test3.caller = ' + test3.caller + '\n\n';
out+= (arguments.caller == test3.caller) + '\n\n';
out+= arguments.caller.callee;
output.value = out;
}
function test3_helper() {
test3();
} test3_helper.fid = true;
</script>
</head>
<body>
<form name="frm01" action="">
<fieldset>
<legend>Test</legend><br>
<textarea name="output" id="output"
cols="64" rows="10"></textarea><br>
<input type="button" value="Test 1"
onClick="test1(arguments.callee)">
<input type="button" value="Test 2"
onClick="test2(arguments.callee)">
<input type="button" value="Test 3" onClick="test3_helper()">
</fieldset>
</form>
</body>
</html>