Closed Bug 1475013 Opened 6 years ago Closed 2 years ago

A lot of time spent in CreateDynamicFunction

Categories

(Web Compatibility :: Desktop, defect, P1)

defect

Tracking

(Not tracked)

RESOLVED INACTIVE

People

(Reporter: zbraniecki, Unassigned)

References

(Depends on 1 open bug)

Details

(Keywords: webcompat:site-wait, Whiteboard: [sitewait])

In latest Nightly on MBP 2013 I got this profile: https://perfht.ml/2NFMXBU

STR:

1) Start Firefox
2) Open http://buffstreamz.com/view/soccer5.php
3) Try to scroll
Nicolas - florian pointed at you as a good first NI on this. Feel free to redirect :)
Flags: needinfo?(nicolas.b.pierron)
Whiteboard: [qf]
The page essentially does this:
---
setInterval(function(){ main(); }, 2000);

function main() {
    function inner() {
        Function("debugger")();
        inner();
    }
    try{ inner(); } catch (e) { }
};

main();
---

So it's not a big surprise we see lots of calls to CreateDynamicFunction until the maximum stack size has been reached and we're saved by "InternalError: too much recursion".
How does Chrome avoid that? Or do they get different JS? And why would anyone do this?
V8's eval cache includes functions created through CreateDynamicFunction, so they only need to parse the function once and then can execute it right away from their cache, whereas we need to parse the function code every time CreateDynamicFunction is called.
Is that actionable? Is that worth pursuing? If the answer is no, feel free to close this bug as wontfix.
Depends on: 1420440
(In reply to Zibi Braniecki [:gandalf][:zibi] from comment #5)
> Is that actionable? Is that worth pursuing? If the answer is no, feel free
> to close this bug as wontfix.

I would say yes but not for this use case.

From what I could gather from a JavaScript developer `Function("debugger")()` might be a way to cheat some linter rules.

Then doing an infinite recursion for being able to hook a debugger highlight that this code was not tested on other browsers, or not meant to go to production.

So for this particular web page, I think this is more likely to be a work for the advocacy team.
Flags: needinfo?(nicolas.b.pierron)
(In reply to Nicolas B. Pierron [:nbp] {backlog: 39} from comment #7)

> From what I could gather from a JavaScript developer
> `Function("debugger")()` might be a way to cheat some linter rules.
> 
> Then doing an infinite recursion for being able to hook a debugger highlight
> that this code was not tested on other browsers, or not meant to go to
> production.
> 
> So for this particular web page, I think this is more likely to be a work
> for the advocacy team.

Adam, is this something the webcompat team can help with? Thanks!
Flags: needinfo?(astevenson)
Whiteboard: [qf] → [qf-]
Yes I will try to reach out. It is ranked 1920 globally and 566 in the US by Alexa.

Contacting:
buffstreamhelp@gmail.com
Flags: needinfo?(astevenson)
Whiteboard: [qf-] → [qf]
Component: JavaScript Engine → Desktop
Priority: -- → P1
Product: Core → Tech Evangelism
Whiteboard: [qf] → [qf-][sitewait]
(In reply to Nicolas B. Pierron [:nbp] {backlog: 39} from comment #7)
> I would say yes but not for this use case.
> 
> From what I could gather from a JavaScript developer
> `Function("debugger")()` might be a way to cheat some linter rules.
> 
> Then doing an infinite recursion for being able to hook a debugger highlight
> that this code was not tested on other browsers, or not meant to go to
> production.
> 
> So for this particular web page, I think this is more likely to be a work
> for the advocacy team.

This is a quite common snippet to prevent users to debug their website.
Just search "setInterval 0xfa0" in search engine and you will see many similar sites.

There is a tool just for this: (see the "Debug Protection" section)
https://javascript-obfuscator.org/
Another case of a site trying to abuse the debugger to block people with the debugging tools.
https://github.com/webcompat/web-bugs/issues/15371#issuecomment-379149246

!function javdev() {
  try {
    !function cir(i)
    {
      (1 !== ('' + i / i).length || 0 === a) && function () {
      }.constructor('debugger') (),
      cir(++i);
    }(0)
  } catch (e) {
    setTimeout(javdev, 500)
  }
}()
So maybe we should just file an issue at <https://github.com/javascript-obfuscator/javascript-obfuscator> to let them know that their "debug protection" <https://github.com/javascript-obfuscator/javascript-obfuscator#debugprotection> can lead to general slow-down of a website?
(In reply to André Bargull [:anba] from comment #12)
> So maybe we should just file an issue at
> <https://github.com/javascript-obfuscator/javascript-obfuscator> to let them
> know that their "debug protection"
> <https://github.com/javascript-obfuscator/javascript-
> obfuscator#debugprotection> can lead to general slow-down of a website?

IDK, it seems they already know this. (see <https://github.com/javascript-obfuscator/javascript-obfuscator#debugprotectioninterval>)

Even if they change their approach or remove this feature, the existing websites will not disappear immediately.
Would it make sense to match the bytecode produced and replace these functions by no-op, unless a Debugger instance exists?
Maybe the debugger should have an option to ignore debugger statements to deal with this "anti-debugger technique"?
(In reply to Jan de Mooij [:jandem] from comment #15)
> Maybe the debugger should have an option to ignore debugger statements to
> deal with this "anti-debugger technique"?

Totally.
Chrome has a nice feature where you can disable a debugger statement by right clicking on the line and selecting a context menu.
I think the reason that hack is calling the Function constructor, rather than just running the `debugger` statement directly, is to defeat exactly that feature.

I'll bet these constant recompilations make the debugger really slow, handling all those onNewScript events.
(In reply to Jim Blandy :jimb from comment #18)
> I'll bet these constant recompilations make the debugger really slow,
> handling all those onNewScript events.

I believe you are right.
I tried to modify this line to make it ignores debugger statement, but the main process is still very busy.
https://searchfox.org/mozilla-central/rev/aff5d4ad5d7fb2919d267cbc23b1d87ae3cf0110/devtools/server/actors/thread.js#1637

Ideally I hope we can improve CreateDynamicFunction, just like what Chrome/Webkit does, and have an option in DevTools to ignore debugger statement.
Product: Tech Evangelism → Web Compatibility

See bug 1547409. Moving webcompat whiteboard tags to keywords.

I don't get this behavior (the one I described in bug 1557158) in Firefox 69.0 on Windows.

I still get it on an older version in Linux.

Performance Impact: --- → -
Whiteboard: [qf-][sitewait] → [sitewait]

The main URL https://home.buffstreamz.com/ loads as expected. The provided URL is not available anymore. The main page has at the moment, only an NFL stream available to watch, which redirects to: http://bfstrs.xyz/watch/nfl.php . Both Chrome and Firefox have issues loading the stream, as they both fail to load it, or load it very slow.

Reporter, is the issue reproducible when watching a stream, or something else on the page? Also, is the URL provided by me valid, or is there another section of the page that exhibits the highlighted issue?

Tested with:

Browser / Version: Firefox Nightly 101.0a1 (2022-04-12) (64-bit)
Operating System: Windows 10 PRO x64

Performance Impact: - → ---
Flags: needinfo?(zibi)

It doesn't load anymore.

Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → INACTIVE
Flags: needinfo?(zibi)
You need to log in before you can comment on or make changes to this bug.