For simple javascript debugging I'll use alerts to show variable values and the like. Is there a way to get the current call stack in javascript to be able to display it in an alert?
Thanks.
Quick and dirty in Gecko-based browsers:
new Error().stack
You can also manually trawl some of the stack using Function.prototype.caller:
var thisFunction = arguments.callee;
var caller = thisFunction.caller;
var callerCaller = caller.caller;
// ...and eventually, assuming no recursion:
var bottomCaller = ...;
assert(bottomCaller.caller === null);
One (possibly large) caveat of the .caller trick is that it doesn't handle recursion -- .caller looks from the top of the stack downward to find the first instance of the function in the stack and then returns its immediate caller, so without being careful you can loop infinitely looking up callers.
Another caveat to caller is that, going forward, if any of your code uses ECMAScript 5's strict mode, the caller property of strict mode functions (or of functions which have themselves been called from strict mode functions) is a so-called "poison pill" which throws a TypeError when accessed. The caller property of "bound" functions (those created by ES5's Function.prototype.bind method) is also a poison pill. These restrictions break the generic stack-walking algorithm, although one could imagine use-specific ways to work around this (entry and exit annotating functions, perhaps).
Do note that stack-walking like this isn't a great idea in production code (as a quick hack for debugging it's fine, tho); at the moment walking up the stack as in the latter example is somewhat expensive in Mozilla's JS engine, and it'll probably throw you out of machine code and back into interpreted code. Also, the stack-walk is O(n2), which might matter if you tend to have complex, deep stacks.
You can use console.trace()
It doesn't display an alert() but print the stacktrace on the debugger console.
Use debugger like Firebug for this if you are in Firefox. Chrome and Opera have build-in debugger. And there are Developers Tools for Internet Explorer.
The best way to debug Javascript is to use Firebug, which includes a full Javascript debugger.
If you're debugging in IE, you can use Visual Web Developer Express (or any other edition of Visual Studio).
If you're debugging IE8, you can use its built-in developer tools, which include a debugger.
It is possible to get the call stack in Javascript; see here.
Have you looked at firebug - and a breakpoint. If it's just for debugging, then this might suffice.
Also - you can have a look Here
This will give you all call stack
working good for me.
var y = 'arguments.callee.caller';
while (eval(y) != undefined) {
stak += eval(y + '.toString()');
y = y + '.caller';
}
alert(stak);
For nodejs debugging, in Visual Studio Code, as of v.1.14.2, it's View->Debug (Ctrl+Shift+D)
Related
I recently started to swap out all my debugger statements with eval('debugger') statements. The reason is that with the plain version, not all "factually/theoretically" visible variables are "practically" visible. This happens because of optimization (see earlier SO question).
With this trick, the problem is like "90% solved" - there are some drawbacks. Apart from longer source code, those are:
When third party libraries are involved, it is not feasible, maybe not even possible to have the debugger -> eval('debugger') transformation done there also.
When I would rather set a break point in the debugger itself, instead of changing the code, that cannot be done - or can it?
When I'm already stopped at a "normal" debugger statement (in third party code, or where I forgot one), there is no way to switch to the desired mode - certainly typing eval('debugger') on the console doesn't help. If I want the functionality, I have to change the debugger statement, and run the code again, which might be a whole lot of work
When I stopped at an eval('debugger') statement, but then use the debugger 'step over/into/out' functionality, I 'lost my special status'.
How can I work around this? Is there a way to tell v8 to interpret all debugger statements by eval('debugger')? Is there a trick with which you can 'go into the other mode' - as if the eval('debugger') statement would magically appear as the next statement after the debugger statement where you're stopped? Do command line options to the chrome executable help? Maybe there is a way in firefox?
I learned about the eval('debugger') trick in an answer to a recent SO question of my own
ANNOUNCEMENT
What I'm going to do next is write a little transpiler for usage within node webserver. The transpiler will insert eval('') statements all over the place (by default once at the beginning/body of every function, and more or fewer of them if so specified in the query string.) Then I can set a breakpoint where the eval statement is, do "step into" and then I got what I want. Then I'm going to answer my own question.
Unless of course, someone will beat me to it. That would be most delightful, as I do have other things to do.
V8 developer here.
Is there a way to tell v8 to interpret all debugger statements by eval('debugger')?
There is currently no way to treat debugger statements or breakpoints as eval("debugger"), but it might be feasible to add a flag that does this. You can file a "feature request" bug at crbug.com/v8/new and ask for a flag that forcibly context-allocates all variables for debugging purposes.
(Side note 1: It's the eval part that has an effect here. Instead of eval('debugger') you could write eval(""); debugger; or debugger; other_code(); eval("");, so long as you have eval somewhere in the function.)
(Side note 2: the tension here is that on the one hand, it's Good™ when the behavior of a program when it is being debugged is the same as when it is not being debugged -- otherwise there might be issues that only show up when debugging, or un-debuggable failures in production mode. On the other hand, sometimes certain deviations are explicitly necessary in order to make debugging possible. I'm not sure on which side of the line this one falls. Context-allocating all variables will reduce performance and increase memory consumption, so if/when such a mode becomes available, you will probably have to (or want to) switch back and forth during your development work; which in particular means that this couldn't simply be the default when DevTools are open.)
Is there a trick with which you can 'go into the other mode' - as if the eval('debugger') statement would magically appear as the next statement after the debugger statement where you're stopped?
No, and there can't be. It's not a "mode" or "special status", it's a decision that has to be made when first parsing/compiling the outer function (the one that contained the variable you want to see within an inner function). Once that time has passed, it's too late to change anything (non-context-allocated variables are just gone), and the only option is to reload.
[EDIT in response to comments:
To clarify what I mean by "not a mode, but a decision": from the scope chain's point of view, the situation is essentially the same as:
var inner;
function outer() {
var foo = "foo";
var bar = "bar";
inner = function() {
console.log(bar);
debugger;
}
// "inner();" here is moved below
}
outer();
inner();
at the point when inner() is called, foo is either still there like bar (if it's context-allocated because at compile time of outer V8 determined that inner will need it), or gone (if V8 determined that it's local to outer and nobody else will need it). If inner contains eval, then it might need all outer-scope variables.
--end of EDIT]
This happens because of optimization
Well... because of an optimization, namely being smart about whether to allocate variables on the stack or in the "context object". This is completely unrelated to what is typically referred to as "optimization of a function", i.e. running them through the optimizing compiler. That's why the %NeverOptimizeFunction hack discussed in the other issue had no effect -- it's an unrelated mechanism.
Executing this snippet in the Chrome console:
function foo() {
return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());
should print 1000 times false, but on some machines will print false for a number of iterations, then true for the rest.
Why is this happening? Is it just a bug?
There is a chromium bug open for this:
Issue 604033 - JIT compiler not preserving method behavior
So yes It's just a bug!
It's actually a V8 JavaScript engine (Wiki) bug.
This engine is used in Chromium, Maxthron, Android OS, Node.js etc.
Relatively simple bug description you can find in this Reddit topic:
Modern JavaScript engines compile JS code into optimized machine code
when it is executed (Just In Time compilation) to make it run faster.
However, the optimization step has some initial performance cost in
exchange for a long term speedup, so the engine dynamically decides
whether a method is worth it depending on how commonly it is used.
In this case there appears to be a bug only in the optimized path,
while the unoptimized path works fine. So at first the method works as
intended, but if it's called in a loop often enough at some point the
engine will decide to optimize it and replaces it with the buggy
version.
This bug seems to have been fixed in V8 itself (commit), aswell as in Chromium (bug report) and NodeJS (commit).
To answer the direct question of why it changes, the bug is in the "JIT" optimisation routine of the V8 JS engine used by Chrome. At first, the code is run exactly as written, but the more you run it, the more potential there is for the benefits of optimisation to outweigh the costs of analysis.
In this case, after repeated execution in the loop, the JIT compiler analyses the function, and replaces it with an optimised version. Unfortunately, the analysis makes an incorrect assumption, and the optimised version doesn't actually produce the correct result.
Specifically, Reddit user RainHappens suggests that it is an error in type propagation:
It also does some type propagation (as in what types a variable etc can be). There's a special "undetectable" type for when a variable is undefined or null. In this case the optimizer goes "null is undetectable, so it can be replaced with the "undefined" string for the comparison.
This is one of the hard problems with optimising code: how to guarantee that code which has been rearranged for performance will still have the same effect as the original.
This was fixed two month ago and will land in Chrome soon (already in Canary).
V8 Issue 1912553002 - Fix 'typeof null' canonicalization in crankshaft
Chromium Issue 604033 - JIT compiler not preserving method behavior
Executing this snippet in the Chrome console:
function foo() {
return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());
should print 1000 times false, but on some machines will print false for a number of iterations, then true for the rest.
Why is this happening? Is it just a bug?
There is a chromium bug open for this:
Issue 604033 - JIT compiler not preserving method behavior
So yes It's just a bug!
It's actually a V8 JavaScript engine (Wiki) bug.
This engine is used in Chromium, Maxthron, Android OS, Node.js etc.
Relatively simple bug description you can find in this Reddit topic:
Modern JavaScript engines compile JS code into optimized machine code
when it is executed (Just In Time compilation) to make it run faster.
However, the optimization step has some initial performance cost in
exchange for a long term speedup, so the engine dynamically decides
whether a method is worth it depending on how commonly it is used.
In this case there appears to be a bug only in the optimized path,
while the unoptimized path works fine. So at first the method works as
intended, but if it's called in a loop often enough at some point the
engine will decide to optimize it and replaces it with the buggy
version.
This bug seems to have been fixed in V8 itself (commit), aswell as in Chromium (bug report) and NodeJS (commit).
To answer the direct question of why it changes, the bug is in the "JIT" optimisation routine of the V8 JS engine used by Chrome. At first, the code is run exactly as written, but the more you run it, the more potential there is for the benefits of optimisation to outweigh the costs of analysis.
In this case, after repeated execution in the loop, the JIT compiler analyses the function, and replaces it with an optimised version. Unfortunately, the analysis makes an incorrect assumption, and the optimised version doesn't actually produce the correct result.
Specifically, Reddit user RainHappens suggests that it is an error in type propagation:
It also does some type propagation (as in what types a variable etc can be). There's a special "undetectable" type for when a variable is undefined or null. In this case the optimizer goes "null is undetectable, so it can be replaced with the "undefined" string for the comparison.
This is one of the hard problems with optimising code: how to guarantee that code which has been rearranged for performance will still have the same effect as the original.
This was fixed two month ago and will land in Chrome soon (already in Canary).
V8 Issue 1912553002 - Fix 'typeof null' canonicalization in crankshaft
Chromium Issue 604033 - JIT compiler not preserving method behavior
Right now I am debugging some weird errors which occur in my GWT (version 2.5.1) application since Firefox 46. The javascript code generated by GWT contains multiple instances of this pattern:
function nullMethod() {
}
var v;
function f() {
f = nullMethod;
v = { name : 'Joe' };
console.log("called");
}
// this is called from multiple places
console.log((f(), v).name);
console.log((f(), v).name);
console.log((f(), v).name);
Seems that this somehow implements the singleton pattern. But for some reason this does not prevent that the initial declared method is invoked again. The string 'called' is printed to the console multiple times.
But if I try to reproduce this with a little test everything works as expected. The observations from above was made by adding console outputs to the generated code (>5MB).
Now the really weird stuff. If I add "console.log(f.toString())" as the first statement of the function, it prints the intial function on the first invocation. All further invocations print the nullMethod.
Can somebody explain what could be the cause? IE11 works fine. Chrome has the same issue as Firefox 46. I just didn't find old Chrome versions to verify since when this behaviour was introduced. Is it valid to overwrite a function declared this way?
jsbin.com gives a warning on the function re-assignment line:
Line 6: 'f' is a function.
The method f in this case is a Java static initializer. Running it more than once will cause problems in the emulated Java, which expects that this can only run a single time when the class is first referenced or loaded (ignoring classloader issues, since GWT doesnt emulate classloaders).
However, sufficiently old copies of GWT wrap up blocks of code in a try/catch block (iirc this was related to IE6 issues), and at the time, JS scope rules had some ambiguity around them which made this code work consistently, since all browsers supported this. This was known as a "sloppy mode self-defining function".
As part of ES2015, it has been decided that the try block has a different scope than the outer "function-hosted" one (i.e. when you declare something as a function foo() {...}, it exists in a high-level scope). See a ton of discussion on this at https://github.com/tc39/ecma262/issues/162.
This change means that some formerly sane programs no longer work correctly - for a time, this included Google Inbox as well as others.
Updating to a newer version of GWT, or using a custom Linker that no longer wraps each block of top-level JS in old GWT should resolve this. If you still must support whatever ancient browser that requires this behavior (with enough code archeology, I'm sure we could find out why GWT initially did it, but I haven't done this yet), you are going to have to find a compromise that works in both ancient and bleeding edge browsers.
I'm working on a web application in HTML/JavaScript, and I want to prevent users from calling functions in their browser console in order to avoid cheating. All these functions are contained in a unique file called functions.js which is loaded in the head of the index.html file.
After a search on the web I found this solution, which works fine in Google Chrome, but it is inefficient in other browsers such as Firefox:
var _z = console;
Object.defineProperty( window, "console", {
get : function(){if( _z._commandLineAPI ){ throw "Script execution not permitted" } return _z; },
set : function(val){ _z = val }
});
Is there a general way to disable functions call from console? Does it depend on the browser or is it just a problem of scoping or maybe something else that I have ignored?
Is there a general way to disable functions call from console?
No. there isn't: Never. Well, apparently, Facebook found a way in Google Chrome to do so: How does Facebook disable the browser's integrated Developer Tools? - though, I would consider it a bug :-)
Is it maybe something else that I have ignored?
Yes. JavaScript is executed client-side, and the client has the full power over it. He can choose whether or not to execute it, how to execute it and modify it as he wants before executing it. Modern developer tools allow the user to execute arbitrary functions in arbitrary scopes when debugging a script.
You can make it harder to introspect and use (call) your code by avoiding to expose your methods in the global scope, and by obfuscating (minifying) the source. However, never trust the client. To avoid cheating, you will have to perform all crucial task on the server. And don't expect all requests to come from your JavaScript code or from a browser at all; you will need to handle arbitrary requests which might be issued by some kind of bot as well.
Rather than eliminating access to the console, just code your javascript so it doesn't pollute the global namespace. It will make it much harder (or in simple cases virtually impossible) for code executed from the console or address bar to execute your code: https://stackoverflow.com/a/1841941/1358220
It's also worth noting, if you have some code you want the user not to be able to edit or execute, move it to the serverside and only expose the result to the client. You're currently trying to fix a bad design design with a bad coding decision. Improve your design and the implementation will take care of itself.
Minify your JavaScript source to obfuscate any meaning. It won't make it impossible to cheat, but really hard to figure out ways to cheat.
if (window.webkitURL) {
var ish, _call = Function.prototype.call;
Function.prototype.call = function () { //Could be wrapped in a setter for _commandLineAPI, to redefine only when the user started typing.
if (arguments.length > 0 && this.name === "evaluate" && arguments [0].constructor.name === "InjectedScriptHost") { //If thisArg is the evaluate function and the arg0 is the ISH
ish = arguments[0];
ish.evaluate = function (e) { //Redefine the evaluation behaviour
throw new Error ('Rejected evaluation of: \n\'' + e.split ('\n').slice(1,-1).join ("\n") + '\'');
};
Function.prototype.call = _call; //Reset the Function.prototype.call
return _call.apply(this, arguments);
}
};
}
If you want to avoid "cheating", you will need server-side verification of user input. The client can only send the server information according to a server-side defined protocol, and thus cheating is impossible, unless your protocol has security leaks (and most protocols do, especially new protocols).
Sandboxes such as the Facebook API, Google Caja and more allow you to arbitrarily enforce any constraints by "re-writing" the language (they run a parser on and basically re-compile user-given code and make everything that is unsafe safe).
This works as long as you can make sure that user code can only run inside these environments. This way code from other users cannot mess with your client, but you can of course still mess with your own client.
For those looking for it today:
This obfuscator tool: https://obfuscator.io has the feature "Debug Protection" this blocks the console and even the inspection mode of your browser.
It also stops any javascript when the inspector was opened.
Works like a charm.