views:

107

answers:

5

Hi

I would like to count the number of calls made to eval in our javascript application.

I came up with the following, but it generates errors. These errors are hard to track, and my knowledge of the app is limited.

Can you tell what is wrong with my code ?

increment = function (){
  var me = arguments.callee;
  if (!me.count) me.count = 0;
  return ++me.count;
}

var oldEval = eval;

eval = function eval(string){    
  console.log('eval number ', increment());
  return oldEval(string);
}

Or to you know an alternative way to count the use of eval ?

thanks

Olivier

A: 

Can you post the errors you are getting? I ran your code in FF 3.5 and didn't have problems.

Justin Swartsel
better to post this as a comment on the question, as it isn't an answer. Welcome to SO! :D
CrazyJugglerDrummer
Yeah, sorry about that. I tried to but there was no option to comment on the question itself. Maybe I don't have enough reputation points?
Justin Swartsel
@CrazyJugglerDrummer: yeah I don't think he can comment until 50 rep.
Roatin Marth
A: 

The only thing that jumps out is your argument name "string"

Try changing it to "str" or something. Some browsers might not like "String" since it is actually a Class name (esp. IE that often ignores case sensitivity sometimes)

Note I tested your code, and it works in Firefox 3.5 (with the Firebug addon installed)

If you don't have a console object defined, or a log method on said console object - you will get errors. (e.g. if Firebug or similar is not installed)

scunliffe
+5  A: 

Unfortunately there is not a watertight way of emulating/wrapping eval, because it isn't a normal function. It can access (both read and write) the local variables of the direct caller.

function testeval() {
    var a= 2;
    eval('a*= 2');
    alert(a); // 4
};

This is magic you can't emulate from a native JavaScript function. You'd have no way from myWrappedEval to get the value of a in the caller or write back the changed value. Whilst you can get hold of the caller function using arguments.caller, there's no way to read the locals of the function invocation.

You'll have to manually insert a call to increment just before each usage of eval you can find in the source. Or, better, remove every call to eval and replace it with better code, making the call total zero. ;-)

bobince
Forgot about that. Depending on what `eval` is being used for this decorating will probably break it altogether. Damn, JS needs `caller.locals()` so badly.
Crescent Fresh
Thanks. The issue is not related to the increment thing, if I remove it, its the same.I'm not sure that the arguments.caller question is the origin of the issue, since it breaks on methods that are not making use of that.
Olivvv
`arguments.caller` is not related to the problem, merely mentioned as a strategy for a workaround (that won't work!). The problem will happen for *any* `eval` call that uses a function's local variables.
bobince
A: 

Try this modified version

var increment = function () {
  var me = arguments.callee;
  if (!me.count) me.count = 0;
  return ++me.count;
}

var oldEval = eval;

eval = function (str) {
  alert('eval number ' + increment());
  return oldEval(str);
}
  • Renamed string to str
  • used alert instead of console.log (which isn't available in all browser)
  • Changed call to alert to use string concatenation
  • changed new eval function to be anonymous (removed eval name)
jitter
Thanks but this doesn't help. points 1 and 4 are not changing anything and I have hundreds of occurrences so I won't use alert();
Olivvv
Ok then replace `alert` again with console.log. So now I assume console.log works for you. Did you consider logging the argument (str) itself and check one which ones it breaks. Then post some samples in your question
jitter
A: 

I came up with a rudimentary solution. It seems to work, at least I can gather some data, but I"m not 100% sure it is correct.

so I just do :

eval = eval;

With that, firebug's profiler is able to count the calls to eval, but does not group that counting, therefore I have to copy and paste to excel, and build a pivot Table in order to get the data.

Olivvv
Say What now? Please elaborate!
Roatin Marth
There is not much to elaborate.eval = eval;after that the calls to eval() are reported by the firebug profiler.However they are counted on multiple lines, so I use excel to sum them all.The firebug's profiler output look like that:eval() 1 0.01% 0.024ms 0.979ms 0.979ms 0.979ms 0.979ms 326 (line 1)eval() 1 0.01% 0.024ms 0.991ms 0.991ms 0.991ms 0.991ms 318 (line 1)eval() 1 0.01% 0.024ms 0.759ms 0.759ms 0.759ms 0.759ms 313 (line 1)This technique can probably by used to count the calls to any other native javascript functions.
Olivvv