473,289 Members | 1,791 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,289 software developers and data experts.

Recursive functions and arguments.callee.caller

Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

So I thought to do:
<script type='text/javascript'>
function myFunc(lev) {
// if (lev) return myFunc(lev-1);
var aStack=[];
nextFunc = arguments.callee;
while (nextFunc) {
aStack.push(nextFunc.name ? nextFunc.name : nextFunc.toString());
nextFunc = nextFunc.caller;
}
return aStack;
}
function foo() { return myFunc(1); }
function bar() { return foo("frob"); }
alert (bar("baz"));
</script>
This works as expected (on FF 1.5+ / IE 6 on my WinXP Pro). However,
if I uncomment the first line of myFunc to make it recursive (making
sure I don't have any unsaved work or other browser windows open), the
function stalls out because arguments.callee.caller==arguments.callee,
so the script goes into an infinite loop.

In other words, myFunc at the lowest level knows it was called by
myFunc (hence I can detect recursion), but I don't see how to determine
how many levels deep myFunc is, nor its original caller. Anyone know
an alternate approach?

Thanks,
Csaba Gabor from Vienna

I did try an approach of getting to the arguments.callee of the caller
(since arguments.callee.caller in [the outer call, ] myFunc(1) is
correct, returning foo), but no dice. I got the same results (of an
infinite loop) after adding the following two lines after nextFunc =
nextFunc.caller;

if (!nextFunc) break;
var nextFunc = nextFunc.arguments.callee;

Mar 19 '06 #1
9 16766
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

So I thought to do:
<script type='text/javascript'>
function myFunc(lev) {
// if (lev) return myFunc(lev-1);
var aStack=[];
nextFunc = arguments.callee;
while (nextFunc) {
aStack.push(nextFunc.name ? nextFunc.name : nextFunc.toString());
nextFunc = nextFunc.caller;
}
return aStack;
}
function foo() { return myFunc(1); }
function bar() { return foo("frob"); }
alert (bar("baz"));
</script>
This works as expected (on FF 1.5+ / IE 6 on my WinXP Pro). However,
if I uncomment the first line of myFunc to make it recursive (making
sure I don't have any unsaved work or other browser windows open), the
function stalls out because arguments.callee.caller==arguments.callee,
so the script goes into an infinite loop.

In other words, myFunc at the lowest level knows it was called by
myFunc (hence I can detect recursion), but I don't see how to determine
how many levels deep myFunc is, nor its original caller. Anyone know
an alternate approach?

Thanks,
Csaba Gabor from Vienna

I did try an approach of getting to the arguments.callee of the caller
(since arguments.callee.caller in [the outer call, ] myFunc(1) is
correct, returning foo), but no dice. I got the same results (of an
infinite loop) after adding the following two lines after nextFunc =
nextFunc.caller;
Not all browsers give function objects a caller property, and I think
the name property of function objects is unique to Gecko. So whatever
you get to work in Firefox/Mozilla/Netscape probably will not work
elsewhere.

if (!nextFunc) break;
var nextFunc = nextFunc.arguments.callee;


The script below is a bit dirty, it works in Firefox but not IE.

I've used the function object's name property but it isn't widely
supported, nor is the name property of arguments.callee (which I guess
is the same thing as arguments.callee is a reference to the current
function object).

You could use toString() and just parse out the function name to get
around lack of support for fnObj.name, it's a bit harder to get around
lack of support for the caller property, but not impossible.
function callFoo(){ foo(); }
function foo(){ bar(); }

function bar()
{
var callObj = arguments.callee;
var callName = callObj.name;
var callChain = [callName];

while ('string' == typeof callName) {
if ( (callObj = callObj.caller) ){
callName = callObj.name;
callChain.push(callName);
} else {
callName = null;
}
}

// Gives top-down order, leave as-is if bottom-up is required
callChain.reverse();
alert(callChain.join('\n'));
}

callFoo();

The bar() function could be turned into a showCallChain() function by
passing it arguments.callee and using that as the initial value of callObj.

It seems to me you are better off having each function call the next
with its arguments.callee.name property as a parameter - again,
callee.name may not be (in fact probably isn't) supported in all browsers.
--
Rob
Mar 20 '06 #2
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

Sorry for my above answer, I missed your point. The problem is that for
recursive functions, the callee and caller properties refer to the same
object.

Try this, loopMe() recurses 'depth' times, then compares callee to caller:

function loopMe(depth, idx){
if (idx<depth){
loopMe(depth, ++idx);
} else {
var obj = arguments.callee;
alert(idx + ': ' + (obj == obj.caller));
}
}

loopMe(5, 0);
You can even do something like:

alert(arguments.callee.caller.caller.caller.caller .name)
after two loops, you'll keep getting 'loopMe'. To keep track of
recursion depth, you'll need to pass ++idx to recursive calls. Once you
enter a recursive function, probably the only way to get the scope chain
using your while algorithm is to pass a reference to the function that
calls the recursive function and start from there.
The ECMAScript Section 10.1.8 says:

"A property is created with name callee and property
attributes { DontEnum }. The initial value of this property
is the Function object being executed. This allows anonymous
functions to be recursive."
And Section 10.2.3 on function code:

"The scope chain is initialised to contain the activation
object followed by the objects in the scope chain stored
in the [[Scope]] property of the Function object."

Based on that and testing, it seems that callee and caller refer to the
original function object, not the activation object that actually calls
the function. This makes sense if you want to use a recursive function
because you want a new 'copy' of the original function object.

Note that arguments.caller was deprecated in Netsacpe's JavaScript
version 1.3, but the function object's caller property is still supported.

The following links offer minimal help:

MSDN:
<URL:
http://msdn.microsoft.com/library/de...489f180ce1.asp
MozDev:
<URL:
http://developer.mozilla.org/en/docs...unction:caller

--
Rob
Mar 20 '06 #3
RobG wrote:
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.
....
The ECMAScript Section 10.1.8 says:

"A property is created with name callee and property
attributes { DontEnum }. The initial value of this property
is the Function object being executed. This allows anonymous
functions to be recursive."

And Section 10.2.3 on function code:

"The scope chain is initialised to contain the activation
object followed by the objects in the scope chain stored
in the [[Scope]] property of the Function object."

Based on that and testing, it seems that callee and caller refer to the
original function object, not the activation object that actually calls
the function. This makes sense if you want to use a recursive function
because you want a new 'copy' of the original function object.


Thanks for your comments, Rob. I didn't follow your conclusion about
it making sense and wanting the copies. Are you saying that it makes
sense as is? Seems to me, I should expect to be able to backtrack up
the call stack. I didn't find any references to
arguments.callee.caller coupled with recursive functions in my
searches, but I did see mentioned __caller__ in one old FF bug report
(https://bugzilla.mozilla.org/show_bug.cgi?id=65683), but I didn't get
so much as "peep" in trying to use it.

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. By the same token,
it's not a (stack) space issue since that stack exists anyway (since
each function higher up the stack has its own, extant and distinct
arguments object). And it's also not on account of possible tail
recursion optimisation because in separate testing I inserted code to
forestall tail recursion.

Csaba Gabor from Vienna

Mar 20 '06 #4
Csaba Gabor said on 21/03/2006 4:03 AM AEST:
RobG wrote:
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:

Inside a function, I'd like to know the call stack. By this I mean
that I'd like to know the function that called this one, that one's
caller and so on.

...
The ECMAScript Section 10.1.8 says:

"A property is created with name callee and property
attributes { DontEnum }. The initial value of this property
is the Function object being executed. This allows anonymous
functions to be recursive."

And Section 10.2.3 on function code:

"The scope chain is initialised to contain the activation
object followed by the objects in the scope chain stored
in the [[Scope]] property of the Function object."

Based on that and testing, it seems that callee and caller refer to the
original function object, not the activation object that actually calls
the function. This makes sense if you want to use a recursive function
because you want a new 'copy' of the original function object.

Thanks for your comments, Rob. I didn't follow your conclusion about
it making sense and wanting the copies. Are you saying that it makes
sense as is? Seems to me, I should expect to be able to backtrack up
the call stack. I didn't find any references to
arguments.callee.caller coupled with recursive functions in my
searches, but I did see mentioned __caller__ in one old FF bug report
(https://bugzilla.mozilla.org/show_bug.cgi?id=65683), but I didn't get
so much as "peep" in trying to use it.


Ah, I think that holds the key. The caller property references the
function object, not the activation object that the now removed
__caller__ property referred to.
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__.

[...]
--
Rob
Mar 21 '06 #5
VK

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>

Mar 21 '06 #6
VK wrote:
function f() {
f.caller != arguments.caller;
}

f.caller refers to the function forced function f to
create the current heap.
No, it does not. There is only one heap for the entire program.
It is really should be explained better than I did -
Which is not too hard.
and definitely better than it's done in ECMA Books.


There are no ECMA Books.
PointedEars
Mar 21 '06 #7
RobG wrote:
Csaba Gabor said on 21/03/2006 4:03 AM AEST:
RobG said on 20/03/2006 3:51 PM AEST:
Csaba Gabor said on 20/03/2006 8:10 AM AEST:
>Inside a function, I'd like to know the call stack. By this I mean
>that I'd like to know the function that called this one, that one's
>caller and so on.

...

Ah, I think that holds the key. The caller property references the
function object, not the activation object that the now removed
__caller__ property referred to.

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__.


To be clear on what is happening [it is as you say], arguments.callee
returns the original function object (and by that I mean the reference
that you get when you define:
function foo(...) {...}
I tested this by calling a function and in the function doing
arguments.callee.funcProp="frob" and checking foo.funcProp after
finishing the function call and sure enough, there was "frob".

The implication is that each time a call is made the function object
has a property, .caller, placed on it that points to the calling
function object ** for the duration of that call **. Sure enough, this
checks out too.

Frankly, this seems like a really whacked out way to go. I haven't
seen anything so far to give me notions to the contrary. Appears to me
that what is needed is a property of arguments that is essentially
..parent, which would point to the arguments object of the activation
object that called this one. In this fashion there would not even need
to be a .caller property anymore, considering that .caller on the
original function object is a crutch anyway (ie. the interpreter is not
making use of it).

Csaba

By the way, Eric Lippert has a really interesting read about activation
objects, execution variables, scopes, this, and more at:
http://blogs.msdn.com/ericlippert/ar...04/414684.aspx

Mar 23 '06 #8
VK

Csaba Gabor wrote:
To be clear on what is happening [it is as you say], arguments.callee
returns the original function object (and by that I mean the reference
that you get when you define:
function foo(...) {...}


Right in opposite order ;-)

arguments.caller returns a reference to the current running instance of
the function (and its functionality and reliability is partially locked
for security reasons). FunctionName.caller returns the reference to the
original function. Read my previous post again, it has some code to
play with.

Also you may try this (narrowed to illustrate this particular issue):

<html>
<head>
<title>callee, caller and stuff</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">

var out = null;

function init() {
out = document.forms[0].elements['out'];
test();
}
// adding a property to init function object:
init.marker = true;

function test() {
if (arguments.caller) {
var s = 'arguments.caller.marker = '
+ arguments.caller.marker + '\n\n';
s+= 'init.marker = ' + init.marker + '\n\n';
out.value = s;
}
}
</script>
</head>

<body onLoad="init()">

<form action="">
<fieldset>
<legend>Output</legend>
<textarea name="out" cols="64" rows="32"></textarea>
</fieldset>
</form>

</body>
</html>

Mar 25 '06 #9
VK

VK wrote:
arguments.caller returns a reference to the current running instance of
the function (and its functionality and reliability is partially locked
for security reasons). FunctionName.caller returns the reference to the
original function. Read my previous post again, it has some code to
play with.

Also you may try this (narrowed to illustrate this particular issue):
<snip> s+= 'init.marker = ' + init.marker + '\n\n';

<snip>

Hum... Either I'm in everyone's ban list already, or everyone found
some sense in it I'm not aware of :-) Sorry I actually grabbed a wrong
demo file - I produced a lot of them while trying to study this
question. The right code (what I meant in my post is):

<html>
<head>
<title>callee, caller and stuff</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">

var out = null;

function init() {
out = document.forms[0].elements['out'];
test();
}

// adding a property to init function object:
init.marker = true;

function test() {
if (arguments.caller) {
var s = 'arguments.caller.marker = '
+ arguments.caller.marker + '\n\n';
// HERE IS THE CHANGE:
s+= 'test.caller.marker = ' + test.caller.marker + '\n\n';
out.value = s;
}
}

</script>
</head>

<body onLoad="init()">

<form action="">
<fieldset>
<legend>Output</legend>
<textarea name="out" cols="64" rows="32"></textarea>
</fieldset>
</form>

</body>
</html>

IE6 (JScript was not patched for caller) gives me:

arguments.caller.marker = undefined
test.caller.marker = true

Mar 27 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Aloo | last post by:
Dear friends, If we declare a recursive function as 'inline' then does it actually convert to an iterative form during compilation ( the executable code is iterative)? Is it possible ? ...
6
by: jeniffer | last post by:
Please give an example of 2 simple mutually recursive functions in C .
7
by: VK | last post by:
I was getting this effect N times but each time I was in rush to just make it work, and later I coudn't recall anymore what was the original state I was working around. This time I nailed the...
12
by: -Lost | last post by:
What in the world is functionName.name good for? That is: function functionName() { return functionName.name; } I mean, I already had to write out the function's name so it seems that it is...
41
by: Harry | last post by:
Hi all, 1)I need your help to solve a problem. I have a function whose prototype is int reclen(char *) This function has to find the length of the string passed to it.But the conditions...
5
by: Digital Puer | last post by:
I got this on an interview: Is it possible to write inline recursive functions? I said yes, but there is no guarantee that the compiler will definitely inline your code even if you write...
34
by: Jorge | last post by:
Why is it listed here : http://www.crockford.com/javascript/recommend.html under "deprecation" ? Without it, how is an anonymous function() going to call itself (recursively) ? I use to...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.