Closed Bug 1628602 Opened 6 years ago Closed 3 years ago

Race condition when trying to enable context menu in `mouseup` handler

Categories

(Core :: DOM: Events, defect, P5)

76 Branch
defect

Tracking

()

RESOLVED INVALID
Tracking Status
firefox75 --- affected
firefox76 --- affected
firefox77 --- affected

People

(Reporter: juraj.masiar, Unassigned)

Details

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0

Steps to reproduce:

  1. open any webpage
  2. open console and execute following code:
window.addEventListener('mousedown', mouseDownHandler, true);

function mouseDownHandler(e) {
  if (e.button === 2) {
    console.log('mose down');
    e.preventDefault();
    window.addEventListener('mouseup', mouseUpHandler, true);
    disableContextMenu(e);
  }
}

function mouseUpHandler(e) {
  enableContextMenu(e);
  window.removeEventListener('mouseup', mouseUpHandler, true);
}

function disableContextMenu(e) {
  window.addEventListener('contextmenu', preventContextMenu, true);     // lock right-click
}

function enableContextMenu(e) {
  window.setTimeout(() => {    // executing this in the next "tick" of the event loop
    window.removeEventListener('contextmenu', preventContextMenu, true);  // unlock right-click
  }, 0);
}

function preventContextMenu(e) {
  e.preventDefault();
  e.stopImmediatePropagation();
}
  1. start pressing right mouse button (to open context menu) - press it at least 20 times (no need to hurry)

Actual results:

There is a good chance (about 10%) that the context menu will be shown even though it should be blocked.

Expected results:

The point of this code is to be able to enable context menu in the mouseup handler. To to this, I use setTimeout function to schedule execution to the next "tick" of the event loop - after all existing tasks and micro-tasks gets executed. I would expect this includes the internal "mouseup" handler used to show default context menu.

This works in Chrome.

Even though using longer timeout (like 10ms) would "fix" the problem, actually performing some slightly performance intensive work (like modifying DOM) in the event handler would cause the issue again, forcing you to use bigger timeout and facing race condition again and again.

The real life implication is that me as a author of ScrollAnywhere extension (and probably other scroll/gestures webextensions as well) that needs to block right click if mouse is moving but unblock it afterwards needs to use these magic delays. And in Firefox 75 the delay 10ms is suddenly not enough anymore.

Managed to reproduce the issue on Windows 10 x64 on Firefox 75.0, Firefox 76.0b4 and on Firefox Nightly 77.0a1 (2020-04-13).

Status: UNCONFIRMED → NEW
Component: Untriaged → DOM: Events
Ever confirmed: true
Product: Firefox → Core

Hi Olli, any thought for this?

Flags: needinfo?(bugs)
Severity: normal → S4
Priority: -- → P5

"// executing this in the next "tick" of the event loop"
is not correct. setTimeout(0) doesn't mean next tick. It means asynchronously later. Other stuff may be handled before it.
It is perfectly possible that one of those setTimeouts just gets called after mousedown.

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