Skip to content

Commit 98dae67

Browse files
committed
[DI] Fix race condition when adding probes at same location (#5619)
If two probes were added at the same location in the code in quick succession, a race condition might occur in which the code thought there were no existing breakpoint at that location when the 2nd probe was about to be added. At that point it would try to add a new breakpoint which would fail since a breakpoint had already been added there by the first probe.
1 parent 709d328 commit 98dae67

File tree

6 files changed

+49
-25
lines changed

6 files changed

+49
-25
lines changed

LICENSE-3rdparty.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require,limiter,MIT,Copyright 2011 John Hurliman
2020
require,lodash.sortby,MIT,Copyright JS Foundation and other contributors
2121
require,lru-cache,ISC,Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors
2222
require,module-details-from-path,MIT,Copyright 2016 Thomas Watson Steen
23+
require,mutexify,MIT,Copyright (c) 2014 Mathias Buus
2324
require,opentracing,MIT,Copyright 2016 Resonance Labs Inc
2425
require,path-to-regexp,MIT,Copyright 2014 Blake Embrey
2526
require,pprof-format,MIT,Copyright 2022 Stephen Belanger

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
"lodash.sortby": "^4.7.0",
107107
"lru-cache": "^7.14.0",
108108
"module-details-from-path": "^1.0.3",
109+
"mutexify": "^1.4.0",
109110
"opentracing": ">=0.12.1",
110111
"path-to-regexp": "^0.1.12",
111112
"pprof-format": "^2.1.0",

packages/dd-trace/src/debugger/devtools_client/breakpoints.js

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

3+
const lock = require('mutexify/promise')()
34
const { getGeneratedPosition } = require('./source-maps')
4-
const lock = require('./lock')()
55
const session = require('./session')
66
const { compile: compileCondition, compileSegments, templateRequiresEvaluation } = require('./condition')
77
const { MAX_SNAPSHOTS_PER_SECOND_PER_PROBE, MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE } = require('./defaults')
@@ -64,14 +64,14 @@ async function addBreakpoint (probe) {
6464
const release = await lock()
6565

6666
try {
67-
log.debug(
68-
'[debugger:devtools_client] Adding breakpoint at %s:%d:%d (probe: %s, version: %d)',
69-
url, lineNumber, columnNumber, probe.id, probe.version
70-
)
71-
7267
const locationKey = generateLocationKey(scriptId, lineNumber, columnNumber)
7368
const breakpoint = locationToBreakpoint.get(locationKey)
7469

70+
log.debug(
71+
'[debugger:devtools_client] %s breakpoint at %s:%d:%d (probe: %s, version: %d)',
72+
breakpoint ? 'Updating' : 'Adding', url, lineNumber, columnNumber, probe.id, probe.version
73+
)
74+
7575
if (breakpoint) {
7676
// A breakpoint already exists at this location, so we need to add the probe to the existing breakpoint
7777
await updateBreakpoint(breakpoint, probe)
@@ -82,10 +82,15 @@ async function addBreakpoint (probe) {
8282
lineNumber: lineNumber - 1, // Beware! lineNumber is zero-indexed
8383
columnNumber
8484
}
85-
const result = await session.post('Debugger.setBreakpoint', {
86-
location,
87-
condition: probe.condition
88-
})
85+
let result
86+
try {
87+
result = await session.post('Debugger.setBreakpoint', {
88+
location,
89+
condition: probe.condition
90+
})
91+
} catch (err) {
92+
throw new Error(`Error setting breakpoint for probe ${probe.id}`, { cause: err })
93+
}
8994
probeToLocation.set(probe.id, locationKey)
9095
locationToBreakpoint.set(locationKey, { id: result.breakpointId, location, locationKey })
9196
breakpointToProbes.set(result.breakpointId, new Map([[probe.id, probe]]))
@@ -120,7 +125,11 @@ async function removeBreakpoint ({ id }) {
120125
if (breakpointToProbes.size === 0) {
121126
await stop() // TODO: Will this actually delete the breakpoint?
122127
} else {
123-
await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
128+
try {
129+
await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
130+
} catch (err) {
131+
throw new Error(`Error removing breakpoint for probe ${id}`, { cause: err })
132+
}
124133
}
125134
} else {
126135
await updateBreakpoint(breakpoint)
@@ -144,12 +153,21 @@ async function updateBreakpoint (breakpoint, probe) {
144153
const condition = compileCompoundCondition(Array.from(probesAtLocation.values()))
145154

146155
if (condition || conditionBeforeNewProbe !== condition) {
147-
await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
156+
try {
157+
await session.post('Debugger.removeBreakpoint', { breakpointId: breakpoint.id })
158+
} catch (err) {
159+
throw new Error(`Error removing breakpoint for probe ${probe.id}`, { cause: err })
160+
}
148161
breakpointToProbes.delete(breakpoint.id)
149-
const result = await session.post('Debugger.setBreakpoint', {
150-
location: breakpoint.location,
151-
condition
152-
})
162+
let result
163+
try {
164+
result = await session.post('Debugger.setBreakpoint', {
165+
location: breakpoint.location,
166+
condition
167+
})
168+
} catch (err) {
169+
throw new Error(`Error setting breakpoint for probe ${probe.id}`, { cause: err })
170+
}
153171
breakpoint.id = result.breakpointId
154172
breakpointToProbes.set(result.breakpointId, probesAtLocation)
155173
}

packages/dd-trace/src/debugger/devtools_client/lock.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/dd-trace/src/debugger/devtools_client/remote_config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

33
const { workerData: { rcPort } } = require('node:worker_threads')
4-
const lock = require('./lock')()
4+
const lock = require('mutexify/promise')()
55
const { addBreakpoint, removeBreakpoint } = require('./breakpoints')
66
const { ackReceived, ackInstalled, ackError } = require('./status')
77
const log = require('../../log')

yarn.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3212,6 +3212,13 @@ multer@^1.4.5-lts.1:
32123212
type-is "^1.6.4"
32133213
xtend "^4.0.0"
32143214

3215+
mutexify@^1.4.0:
3216+
version "1.4.0"
3217+
resolved "https://registry.yarnpkg.com/mutexify/-/mutexify-1.4.0.tgz#b7f4ac0273c81824b840887c6a6e0bfab14bbe94"
3218+
integrity sha512-pbYSsOrSB/AKN5h/WzzLRMFgZhClWccf2XIB4RSMC8JbquiB0e0/SH5AIfdQMdyHmYtv4seU7yV/TvAwPLJ1Yg==
3219+
dependencies:
3220+
queue-tick "^1.0.0"
3221+
32153222
natural-compare@^1.4.0:
32163223
version "1.4.0"
32173224
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -3687,6 +3694,11 @@ qs@6.13.0:
36873694
dependencies:
36883695
side-channel "^1.0.6"
36893696

3697+
queue-tick@^1.0.0:
3698+
version "1.0.1"
3699+
resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
3700+
integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
3701+
36903702
rambda@^7.4.0:
36913703
version "7.5.0"
36923704
resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.5.0.tgz#1865044c59bc0b16f63026c6e5a97e4b1bbe98fe"

0 commit comments

Comments
 (0)