Closed Bug 1703953 Opened 5 years ago Closed 4 years ago

Prevent instanceof uses against DOM interfaces and prefer .isInstance()

Categories

(Developer Infrastructure :: Lint and Formatting, enhancement)

enhancement

Tracking

(firefox101 fixed)

RESOLVED FIXED
101 Branch
Tracking Status
firefox101 --- fixed

People

(Reporter: saschanaz, Assigned: saschanaz)

References

Details

Attachments

(3 files)

No description provided.

So I now have a working rule, but not sure how can I selectively run it on privileged scripts. I see use-ownerGlobal (which also is for chrome-context only) is manually turned off on a few directories, but instanceof is used in many many more files than ownerGlobal, so I need to detect chrome context automatically and reliably. Is there an existing way to do that?

Flags: needinfo?(gijskruitbosch+bugs)

Standard8 is probably the best person to answer such questions.

Flags: needinfo?(gijskruitbosch+bugs) → needinfo?(standard8)

(In reply to Kagami :saschanaz from comment #1)

So I now have a working rule, but not sure how can I selectively run it on privileged scripts. I see use-ownerGlobal (which also is for chrome-context only) is manually turned off on a few directories, but instanceof is used in many many more files than ownerGlobal, so I need to detect chrome context automatically and reliably. Is there an existing way to do that?

Unfortunately we don't really have a good proxy for what's privileged or not. We know that jsms are definitely privileged, and we can filter on those. We could probably skip it on tests as well.

For the rest of a files, we don't have a good way to tell, some are in-content pages, some are privileged code. Unless we could just assume everything is privileged?

Flags: needinfo?(standard8)

Why does it need to be restricted to chrome contexts?

We could probably skip it on tests as well.

There are many tests that runs on chrome context, so no 😬

Why does it need to be restricted to chrome contexts?

Because .isInstance() is only available in chrome context. (TC39 has been reluctant to standardize it.)

Gijs has just reminded me that we do have the browser-window environment.

Unfortunately environments can't specify rules, and we can't define configurations in the same way as we do for environments. Ideally we'd make sure these files were split with directory names or something, but that is likely to be a bigger job.

What might get us to a place where we can at least have a curated list is:

  • Create a new configuration (see tools/lint/eslint/eslint-plugin-mozilla/lib/configs/) which enables the new rule.
  • Enable the configuration for all jsms and every file that is in the browser-window environment.
    • I suspect we'd have to manually curate and update the list of browser-window environment,
  • Potentially move the privileged environment from the recommended config to the new configuration, and also ensure it is enabled for jsms.
    • Doing this additional step would help us find other files that are privileged but not currently jsms nor browser-window.

(In reply to Kagami :saschanaz from comment #6)

We could probably skip it on tests as well.

There are many tests that runs on chrome context, so no 😬

Is this rule for a transition phase? Is there a point where we could get to where using instanceof in chrome code would simply throw an error and that is all handled by JS?

I'm just wondering if it might be better/easier to handle this from a js perspective rather than linting.

Side note: enabling on tests would be easy, though we'd have to assume that all files in the test directory are chrome privileged.

What might get us to a place where we can at least have a curated list is:

Hmm, I could cause crash for every chrome context instanceof call and enable the config for all the failing files.

Is there a point where we could get to where using instanceof in chrome code would simply throw an error and that is all handled by JS?

That should be possible, but doing so still requires converting existing expressions or otherwise so many tests will start failing that fixing them by hand will be impractical.

(In reply to Kagami :saschanaz from comment #9)

Is there a point where we could get to where using instanceof in chrome code would simply throw an error and that is all handled by JS?

That should be possible, but doing so still requires converting existing expressions or otherwise so many tests will start failing that fixing them by hand will be impractical.

As a starting point, we could at least enable the rule as a warning for jsms - similar to what we've done for the OS.File removal. That would cover a lot of code and start helping to get it changed.

Attachment #9214560 - Attachment description: WIP: Bug 1703953 - Part 1: Implement mozilla/use-isinstance rule → Bug 1703953 - Part 1: Implement mozilla/use-isinstance rule r=gijs,mossop
Attachment #9268940 - Attachment description: WIP: Bug 1703953 - Part 2: Apply mozilla/use-isInstance rules → Bug 1703953 - Part 2: Apply mozilla/use-isInstance rules for .jsm files r=gijs,mossop
Pushed by krosylight@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/eaf6d4c353be Part 1: Implement mozilla/use-isinstance rule r=Gijs,Standard8 https://hg.mozilla.org/integration/autoland/rev/8151244bda18 Part 2: Apply mozilla/use-isInstance rules for .jsm files r=webdriver-reviewers,pip-reviewers,mhowell,Gijs,whimboo https://hg.mozilla.org/integration/autoland/rev/871a1fac289e Part 3: Apply mozilla/use-isInstance to devtools r=julienw

We also got this type of failures caused by this bug: https://treeherder.mozilla.org/logviewer?job_id=372699045&repo=autoland

Okay, so I found an unexpected result.

Modifying getFromWindow() in toolkit/components/extensions/WebNavigationFrames.jsm as below causes error:

  getFromWindow(target) {
    if (target instanceof Window) {
      console.debug(`isInstance: ${Window.isInstance(target)}`);
      console.debug(`instanceof: ${target instanceof Window}`);
    }
    if (Window.isInstance(target)) {
      return getFrameId(BrowsingContext.getFromWindow(target));
    }
    return -1;
  },

With ./mach mochitest toolkit/components/extensions/test/mochitest/test_ext_contentscript_getFrameId.html, the log says:

 0:37.35 INFO Content script loaded on: https://example.org/tests/toolkit/components/extensions/test/mochitest/file_with_xorigin_frame.html
 0:37.39 GECKO(8200) console.debug: "isInstance: true"
 0:37.39 GECKO(8200) console.debug: "instanceof: true"
 0:37.39 GECKO(8200) console.debug: "isInstance: true"
 0:37.41 GECKO(8200) console.debug: "instanceof: true"
 0:37.41 GECKO(8200) console.debug: "isInstance: false"
 0:37.41 GECKO(8200) console.debug: "instanceof: true"
 0:37.41 GECKO(8200) JavaScript error: undefined, line 0: Error: Invalid argument
 0:37.41 GECKO(8200) Console message: [JavaScript Error: "Error: Invalid argument" {file: "undefined" line: 0}]

But per my understanding isInstance should be a strict superset of instanceof. Not sure what's happening here, since both should be using the same backend InterfaceHasInstance.

Hi WebIDL people, do you have any idea?

Flags: needinfo?(peterv)
Flags: needinfo?(krosylight)
Flags: needinfo?(echen)
Depends on: 1762965

Found the cause, will fix it in bug 1762965.

Flags: needinfo?(peterv)
Flags: needinfo?(echen)
Pushed by krosylight@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/d046c96ef135 Part 1: Implement mozilla/use-isinstance rule r=Gijs,Standard8 https://hg.mozilla.org/integration/autoland/rev/5ba4b0a5dd34 Part 2: Apply mozilla/use-isInstance rules for .jsm files r=webdriver-reviewers,pip-reviewers,mhowell,Gijs,whimboo https://hg.mozilla.org/integration/autoland/rev/b617178ef491 Part 3: Apply mozilla/use-isInstance to devtools r=julienw
Depends on: 1769621
Product: Firefox Build System → Developer Infrastructure
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: