Figure out why opening a toolbox on certain workers works only once.

VERIFIED FIXED in Firefox 47

Status

()

Firefox
Developer Tools: about:debugging
VERIFIED FIXED
2 years ago
2 years ago

People

(Reporter: janx, Assigned: ejpbruel)

Tracking

unspecified
Firefox 47
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(firefox47+ fixed)

Details

Attachments

(2 attachments)

(Reporter)

Description

2 years ago
In the new "about:debugging" page, sometimes debugging a Worker twice fails.

Steps:
1. Navigate to "about:debugging".
2. Switch to "Workers" tab.
3. Click on the "Debug" button next to a chrome-privileged worker (in "Other Workers"). A toolbox opens.
4. Close the toolbox, and click on the same button again.

Expected:
- The toolbox reopens and works as before.

Actual:
- A blank toolbox opens (the debugger is empty, showing no sources or code).
(Reporter)

Updated

2 years ago
No longer blocks: 1196785
Depends on: 1196785
(Reporter)

Comment 1

2 years ago
Eddy, could you please have a look at this?
Assignee: nobody → ejpbruel
You say it fails sometimes - does it always fail on chrome-priv workers or sometimes fail across all worker types?  Are there any errors showing out in stdout / jsconsole when this happens?

Also, would you be able to make a mochitest that reproduces this issue?
Flags: needinfo?(janx)
(Reporter)

Comment 3

2 years ago
Sorry about the confusing use of "sometimes". It actually fails systematically for "Other Workers" (corresponding to TYPE_DEDICATED, but it looks like we only get chrome-privileges workers there), while the bug never happens for "Service Workers" or "Shared Workers".

I'll try to reproduce and see if there are any errors associated to that problem (I used to see bug 1207506's messages, but I'm not sure if they're related to this issue).

Good point about writing a mochitest. I filed bug 1215594 to add about:debugging mochitests, and the bug described here is indeed an ideal candidate for such a test.
Blocks: 1215594
Flags: needinfo?(janx)
(Reporter)

Comment 4

2 years ago
Updates:
- This problem only happens with chrome-privileged workers (like "SessionWorker" in "Other Workers").
- It doesn't happen with Service Workers, Shared Workers, or unprivileged web workers (they also show up in "Other Workers").
- When I open a toolbox on a chrome-privileged worker, I always see several "TypeError: Services.io is undefind" errors (as described in bug 1207506), even the first time.
- When I open a toolbox on a chrome-privileged worker for the second time (so only when this bug happens), I see the following error message:

> JavaScript error: resource://gre/modules/commonjs/toolkit/loader.js -> resource:///modules/devtools/client/sourceeditor/editor.js, line 1166: TypeError: cm is undefined

I'm not sure if the Services.io error is related, but the undefined `cm` looks to be the key problem here.
I think the cause is Bug 1207506.  I returned early (return "foo") in dirname and joinURI in https://dxr.mozilla.org/mozilla-central/source/devtools/shared/path.js and it seems the toolbox can be opened a second time.  We should leave this open to confirm afterwards, but I believe it will be fixed by 1207506
Depends on: 1207506
(Reporter)

Updated

2 years ago
Component: Developer Tools → Developer Tools: about:debugging
(Reporter)

Comment 6

2 years ago
[Tracking Requested - why for this release]: Breaks the new Service Worker & Push features that we'd like to announce with Developer Edition 47.
Blocks: 1212
No longer blocks: 1215594
tracking-firefox47: --- → ?
(Reporter)

Updated

2 years ago
Blocks: 1215594
No longer blocks: 1212
(Assignee)

Comment 7

2 years ago
According to Jan, the patch for bug 1207506 does not fix the issue. Putting this bug on my todo list for tomorrow.
(Reporter)

Comment 8

2 years ago
Eddy, could you please have a look at this?

STR:
1. Go to about:debugging#workers
2. Click on "Debug" next to any Worker (e.g. "Other Workers" > "SessionWorker.js")
3. A seemingly functional toolbox opens
4. Close that toolbox, and click the same "Debug" button again

Expected:
- Another function toolbox opens

Actual:
- A broken toolbox opens (blank with only an "x" button). If you repeat step 4 again no toolbox opens at all.



Full RDP replay:

### OPEN TOOLBOX THE FIRST TIME ###

DBG-SERVER: Packet 5 sent to "server1.conn0.worker2"
DBG-SERVER: Received packet 5: {
  "to": "server1.conn0.worker2",
  "type": "attach"
}
DBG-SERVER: Packet 6 sent from "server1.conn0.worker2"
DBG-SERVER: Received packet 6: {
  "type": "attached",
  "url": "resource:///modules/sessionstore/SessionWorker.js",
  "from": "server1.conn0.worker2"
}
DBG-SERVER: Packet 7 sent to "server1.conn0.worker2"
DBG-SERVER: Received packet 7: {
  "to": "server1.conn0.worker2",
  "type": "connect",
  "options": {
    "useSourceMaps": true,
    "autoBlackBox": true,
    "pauseOnExceptions": false,
    "ignoreCaughtExceptions": true
  }
}
DBG-SERVER: Packet 8 sent from "server1.conn0.worker2"
DBG-SERVER: Received packet 8: {
  "type": "connected",
  "threadActor": "server1.conn0.worker2/context1",
  "consoleActor": "server1.conn0.worker2/console2",
  "from": "server1.conn0.worker2"
}
DBG-SERVER: Packet 9 sent to "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 9: {
  "to": "server1.conn0.worker2/context1",
  "type": "attach",
  "options": {
    "useSourceMaps": true,
    "autoBlackBox": true,
    "pauseOnExceptions": false,
    "ignoreCaughtExceptions": true
  }
}
DBG-SERVER: Packet 10 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Packet 11 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 10: {
  "from": "server1.conn0.worker2/context1",
  "type": "newGlobal"
}
DBG-SERVER: Received packet 11: {
  "from": "server1.conn0.worker2/context1",
  "type": "paused",
  "actor": "server1.conn0.worker2/pause3",
  "poppedFrames": [],
  "why": {
    "type": "attached"
  }
}
DBG-SERVER: Packet 12 sent to "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 12: {
  "to": "server1.conn0.worker2/context1",
  "type": "resume",
  "resumeLimit": null
}
DBG-SERVER: Packet 13 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 13: {
  "from": "server1.conn0.worker2/context1",
  "type": "resumed"
}
DBG-SERVER: Packet 14 sent to "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 14: {
  "to": "server1.conn0.worker2/context1",
  "type": "reconfigure",
  "options": {
    "observeAsmJS": true
  }
}
DBG-SERVER: Packet 15 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 15: {
  "from": "server1.conn0.worker2/context1"
}
DBG-SERVER: Packet 16 sent to "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 16: {
  "to": "server1.conn0.worker2/context1",
  "type": "sources"
}
DBG-SERVER: Packet 17 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 17: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source4",
    "url": "resource://gre/modules/osfile/osfile_unix_back.jsm",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": null
  }
}
DBG-SERVER: Packet 18 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 18: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source5",
    "url": "resource://gre/modules/osfile/osfile_shared_allthreads.jsm",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": "resource://gre/modules/workers/require.js",
    "introductionType": "Function"
  }
}
DBG-SERVER: Packet 19 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 19: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source6",
    "url": "resource://gre/modules/osfile/osfile_unix_allthreads.jsm",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": "resource://gre/modules/workers/require.js",
    "introductionType": "Function"
  }
}
DBG-SERVER: Packet 20 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 20: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source7",
    "url": "resource://gre/modules/osfile/ospath_unix.jsm",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": "resource://gre/modules/workers/require.js",
    "introductionType": "Function"
  }
}
DBG-SERVER: Packet 21 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 21: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source8",
    "url": "resource://gre/modules/lz4.js",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": "resource://gre/modules/workers/require.js",
    "introductionType": "Function"
  }
}
DBG-SERVER: Packet 22 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 22: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source9",
    "url": "resource://gre/modules/lz4_internal.js",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": "resource://gre/modules/workers/require.js",
    "introductionType": "Function"
  }
}
DBG-SERVER: Packet 23 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Packet 24 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Packet 25 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Packet 26 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 23: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source10",
    "url": "resource://gre/modules/osfile/osfile_unix_front.jsm",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": null
  }
}
DBG-SERVER: Received packet 24: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source11",
    "url": "resource:///modules/sessionstore/SessionWorker.js",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": null
  }
}
DBG-SERVER: Received packet 25: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source12",
    "url": "resource://gre/modules/osfile/osfile_shared_front.jsm",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": null
  }
}
DBG-SERVER: Received packet 26: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source13",
    "url": "resource://gre/modules/workers/require.js",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": null
  }
}
DBG-SERVER: Packet 27 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 27: {
  "from": "server1.conn0.worker2/context1",
  "type": "newSource",
  "source": {
    "actor": "server1.conn0.worker2/source14",
    "url": "resource://gre/modules/workers/PromiseWorker.js",
    "addonID": null,
    "addonPath": null,
    "isBlackBoxed": false,
    "isPrettyPrinted": false,
    "introductionUrl": "resource://gre/modules/workers/require.js",
    "introductionType": "Function"
  }
}
DBG-SERVER: Packet 28 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 28: {
  "sources": [
    {
      "actor": "server1.conn0.worker2/source4",
      "url": "resource://gre/modules/osfile/osfile_unix_back.jsm",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": null
    },
    {
      "actor": "server1.conn0.worker2/source5",
      "url": "resource://gre/modules/osfile/osfile_shared_allthreads.jsm",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": "resource://gre/modules/workers/require.js",
      "introductionType": "Function"
    },
    {
      "actor": "server1.conn0.worker2/source6",
      "url": "resource://gre/modules/osfile/osfile_unix_allthreads.jsm",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": "resource://gre/modules/workers/require.js",
      "introductionType": "Function"
    },
    {
      "actor": "server1.conn0.worker2/source7",
      "url": "resource://gre/modules/osfile/ospath_unix.jsm",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": "resource://gre/modules/workers/require.js",
      "introductionType": "Function"
    },
    {
      "actor": "server1.conn0.worker2/source8",
      "url": "resource://gre/modules/lz4.js",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": "resource://gre/modules/workers/require.js",
      "introductionType": "Function"
    },
    {
      "actor": "server1.conn0.worker2/source9",
      "url": "resource://gre/modules/lz4_internal.js",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": "resource://gre/modules/workers/require.js",
      "introductionType": "Function"
    },
    {
      "actor": "server1.conn0.worker2/source10",
      "url": "resource://gre/modules/osfile/osfile_unix_front.jsm",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": null
    },
    {
      "actor": "server1.conn0.worker2/source11",
      "url": "resource:///modules/sessionstore/SessionWorker.js",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": null
    },
    {
      "actor": "server1.conn0.worker2/source12",
      "url": "resource://gre/modules/osfile/osfile_shared_front.jsm",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": null
    },
    {
      "actor": "server1.conn0.worker2/source13",
      "url": "resource://gre/modules/workers/require.js",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": null
    },
    {
      "actor": "server1.conn0.worker2/source14",
      "url": "resource://gre/modules/workers/PromiseWorker.js",
      "addonID": null,
      "addonPath": null,
      "isBlackBoxed": false,
      "isPrettyPrinted": false,
      "introductionUrl": "resource://gre/modules/workers/require.js",
      "introductionType": "Function"
    }
  ],
  "from": "server1.conn0.worker2/context1"
}
DBG-SERVER: Packet 29 sent to "server1.conn0.worker2/source8"
DBG-SERVER: Received packet 29: {
  "to": "server1.conn0.worker2/source8",
  "type": "source"
}
DBG-SERVER: Packet 30 sent from "server1.conn0.worker2/source8"
DBG-SERVER: Received packet 30: {
  "from": "server1.conn0.worker2/source8",
  "source": "[redacted]",
  "contentType": "text/javascript"
}

### CLOSE TOOLBOX ###

DBG-SERVER: Packet 31 sent to "server1.conn0.worker2"
DBG-SERVER: Received packet 31: {
  "to": "server1.conn0.worker2",
  "type": "detach"
}
DBG-SERVER: Packet 32 sent from "server1.conn0.worker2"
DBG-SERVER: Received packet 32: {
  "type": "detached",
  "from": "server1.conn0.worker2"
}

### TRY TO RE-OPEN TOOLBOX ###

DBG-SERVER: Packet 33 sent to "server1.conn0.worker2"
DBG-SERVER: Received packet 33: {
  "to": "server1.conn0.worker2",
  "type": "attach"
}
DBG-SERVER: Packet 34 sent from "server1.conn0.worker2"
DBG-SERVER: Received packet 34: {
  "type": "attached",
  "url": "resource:///modules/sessionstore/SessionWorker.js",
  "from": "server1.conn0.worker2"
}
DBG-SERVER: Packet 35 sent to "server1.conn0.worker2"
DBG-SERVER: Received packet 35: {
  "to": "server1.conn0.worker2",
  "type": "connect",
  "options": {
    "useSourceMaps": true,
    "autoBlackBox": true,
    "pauseOnExceptions": false,
    "ignoreCaughtExceptions": true
  }
}
DBG-SERVER: Packet 36 sent from "server1.conn0.worker2"
DBG-SERVER: Received packet 36: {
  "type": "connected",
  "threadActor": "server1.conn0.worker2/context1",
  "consoleActor": "server1.conn0.worker2/console2",
  "from": "server1.conn0.worker2"
}
DBG-SERVER: Packet 37 sent to "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 37: {
  "to": "server1.conn0.worker2/context1",
  "type": "attach",
  "options": {
    "useSourceMaps": true,
    "autoBlackBox": true,
    "pauseOnExceptions": false,
    "ignoreCaughtExceptions": true
  }
}
DBG-SERVER: Packet 38 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Packet 39 sent from "server1.conn0.worker2/context1"
DBG-SERVER: Received packet 38: {
  "from": "server1.conn0.worker2/context1",
  "type": "newGlobal"
}
DBG-SERVER: Received packet 39: {
  "from": "server1.conn0.worker2/context1",
  "type": "paused",
  "actor": "server1.conn0.worker2/pause3",
  "poppedFrames": [],
  "why": {
    "type": "attached"
  }
}

### OOPS, NEW TOOLBOX IS BLANK ###
(Reporter)

Comment 9

2 years ago
Created attachment 8721969 [details]
broken-toolbox.png

This is what the toolbox looks like the second time we launch it.
(Assignee)

Comment 10

2 years ago
The problem is this:

When you call attachThread on a WorkerClient, it creates and registers a ThreadClient. When we detach from the WorkerClient, we never unregister the ThreadClient.

The next time we open the toolbox, we create a new WorkerClient, but for the same worker actor. When we call attachThread on the new WorkerClient, we create a new connection to same worker actor as before. This connection thus uses the same prefix as the previous one, but its still a new connection, so it has its actorID allocator reset. As a result, we end up with a new ThreadActor with the exact same prefix + id as the previous one.

Because their actor IDs are the same, as far as the client is concerned, this new ThreadActor is the same as the previous one. Since we never unregistered the client for the previous ThreadActor, the call to registerClient will throw an exception. But since we were calling registerClient in a promise, this exception is swallowed silently.
(Assignee)

Comment 11

2 years ago
Created attachment 8722458 [details] [diff] [review]
When detaching from a WorkerClient, unregister its ThreadClient.

Luckily, the fix is simple. When we detach from the WorkerClient, we explicitly unregister it from the client. We just need to do the same for its ThreadClient, provided one exists.
Attachment #8722458 - Flags: review?(janx)
(Reporter)

Comment 12

2 years ago
Comment on attachment 8722458 [details] [diff] [review]
When detaching from a WorkerClient, unregister its ThreadClient.

Review of attachment 8722458 [details] [diff] [review]:
-----------------------------------------------------------------

Works like a charm! Thanks a lot for fixing this Eddy.
Attachment #8722458 - Flags: review?(janx) → review+
(Assignee)

Comment 13

2 years ago
Try run for this patch:
https://treeherder.mozilla.org/#/jobs?repo=try&revision=a71582d511c3
(Reporter)

Comment 14

2 years ago
Try is green.
Keywords: checkin-needed

Comment 15

2 years ago
https://hg.mozilla.org/integration/fx-team/rev/585bca5e6a8d
Keywords: checkin-needed

Comment 16

2 years ago
bugherder
https://hg.mozilla.org/mozilla-central/rev/585bca5e6a8d
Status: NEW → RESOLVED
Last Resolved: 2 years ago
status-firefox47: --- → fixed
Resolution: --- → FIXED
Target Milestone: --- → Firefox 47
Jan, could you please verify this issue is fixed as expected on a latest Nightly build? Thanks!
Flags: needinfo?(janx)

Updated

2 years ago
tracking-firefox47: ? → +
(Reporter)

Comment 18

2 years ago
Ritu, I confirm that on the latest Nighly, opening a toolbox multiple times on the same target in about:debugging works perfectly fine! \o/
Status: RESOLVED → VERIFIED
Flags: needinfo?(janx)
(In reply to Jan Keromnes [:janx] from comment #18)
> Ritu, I confirm that on the latest Nighly, opening a toolbox multiple times
> on the same target in about:debugging works perfectly fine! \o/

Awesome! Thank you. :)
You need to log in before you can comment on or make changes to this bug.