Skip to content

Commit a64340b

Browse files
authored
fix shimmer slow shim by removing support for unwrap (#5557)
1 parent 1eefc0a commit a64340b

5 files changed

Lines changed: 20 additions & 149 deletions

File tree

integration-tests/package-guardrails/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ try {
1111
} catch (e) {
1212
const fastify = require('fastify')
1313

14-
console.log(fastify.toString().startsWith('function shim'))
14+
console.log(fastify.toString().startsWith('function fastifyWithTrace'))
1515
}

packages/datadog-shimmer/src/shimmer.js

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
const log = require('../../dd-trace/src/log')
44

5-
// Use a weak map to avoid polluting the wrapped function/method.
6-
const unwrappers = new WeakMap()
7-
85
function copyProperties (original, wrapped) {
96
// TODO getPrototypeOf is not fast. Should we instead do this in specific
107
// instrumentations where needed?
@@ -27,21 +24,13 @@ function copyProperties (original, wrapped) {
2724
function wrapFunction (original, wrapper) {
2825
if (typeof original === 'function') assertNotClass(original)
2926

30-
let delegate = safeMode
27+
const wrapped = safeMode
3128
? safeWrapper(original, wrapper)
3229
: wrapper(original)
3330

34-
const shim = function shim () {
35-
return delegate.apply(this, arguments)
36-
}
37-
38-
unwrappers.set(shim, () => {
39-
delegate = original
40-
})
41-
42-
if (typeof original === 'function') copyProperties(original, shim)
31+
if (typeof original === 'function') copyProperties(original, wrapped)
4332

44-
return shim
33+
return wrapped
4534
}
4635

4736
const wrapFn = function (original, delegate) {
@@ -99,8 +88,6 @@ function wrapMethod (target, name, wrapper, noAssert) {
9988
if (typeof original === 'function') copyProperties(original, wrapped)
10089

10190
if (descriptor) {
102-
unwrappers.set(wrapped, () => Object.defineProperty(target, name, descriptor))
103-
10491
if (descriptor.get || descriptor.set) {
10592
attributes.get = () => wrapped
10693
} else {
@@ -114,7 +101,6 @@ function wrapMethod (target, name, wrapper, noAssert) {
114101
})
115102
}
116103
} else { // no descriptor means original was on the prototype
117-
unwrappers.set(wrapped, () => delete target[name])
118104
attributes.value = wrapped
119105
attributes.writable = true
120106
}
@@ -218,18 +204,6 @@ function wrap (target, name, wrapper) {
218204
: wrapMethod(target, name, wrapper)
219205
}
220206

221-
function unwrap (target, name) {
222-
if (!target) return target // no target to unwrap
223-
224-
const unwrapper = unwrappers.get(name ? target[name] : target)
225-
226-
if (!unwrapper) return target // target is already unwrapped or isn't wrapped
227-
228-
unwrapper()
229-
230-
return target
231-
}
232-
233207
function massWrap (targets, names, wrapper) {
234208
targets = toArray(targets)
235209
names = toArray(names)
@@ -241,17 +215,6 @@ function massWrap (targets, names, wrapper) {
241215
}
242216
}
243217

244-
function massUnwrap (targets, names) {
245-
targets = toArray(targets)
246-
names = toArray(names)
247-
248-
for (const target of targets) {
249-
for (const name of names) {
250-
unwrap(target, name)
251-
}
252-
}
253-
}
254-
255218
function toArray (maybeArray) {
256219
return Array.isArray(maybeArray) ? maybeArray : [maybeArray]
257220
}
@@ -294,7 +257,5 @@ module.exports = {
294257
wrap,
295258
wrapFunction,
296259
massWrap,
297-
unwrap,
298-
massUnwrap,
299260
setSafe
300261
}

packages/datadog-shimmer/test/shimmer.spec.js

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -166,28 +166,6 @@ describe('shimmer', () => {
166166
expect(count).to.have.property('enumerable', false)
167167
})
168168

169-
it('should unwrap a method', () => {
170-
const count = inc => inc
171-
const obj = { count }
172-
173-
shimmer.wrap(obj, 'count', count => inc => count(inc) + 1)
174-
shimmer.unwrap(obj, 'count')
175-
176-
expect(obj.count(1)).to.equal(1)
177-
})
178-
179-
it('should unwrap a method from the prototype', () => {
180-
const count = inc => inc
181-
const obj = {}
182-
183-
Object.setPrototypeOf(obj, { count })
184-
185-
shimmer.wrap(obj, 'count', count => inc => count(inc) + 1)
186-
shimmer.unwrap(obj, 'count')
187-
188-
expect(obj).to.not.have.ownProperty('count')
189-
})
190-
191169
it('should validate that there is a target object', () => {
192170
expect(() => shimmer.wrap()).to.throw()
193171
})
@@ -212,22 +190,6 @@ describe('shimmer', () => {
212190
expect(() => shimmer.wrap({ a: () => {} }, 'a', 'notafunction')).to.throw()
213191
})
214192

215-
it('should not throw when unwrapping without a target', () => {
216-
expect(() => shimmer.unwrap(null, 'a')).to.not.throw()
217-
})
218-
219-
it('should not throw when unwrapping without a method', () => {
220-
expect(() => shimmer.unwrap({}, 'a')).to.not.throw()
221-
})
222-
223-
it('should not throw when unwrapping an invalid type', () => {
224-
expect(() => shimmer.unwrap({ a: 'b' }, 'a')).to.not.throw()
225-
})
226-
227-
it('should not throw when unwrapping a method that was not wrapped', () => {
228-
expect(() => shimmer.unwrap({ a: () => {} }, 'a')).to.not.throw()
229-
})
230-
231193
describe('safe mode', () => {
232194
let obj
233195

@@ -539,34 +501,6 @@ describe('shimmer', () => {
539501
expect(Object.getOwnPropertyNames(wrapped)).to.not.include('test')
540502
})
541503

542-
it('should unwrap a function', () => {
543-
const count = inc => inc
544-
545-
const wrapped = shimmer.wrapFunction(count, count => inc => count(inc) + 1)
546-
547-
shimmer.unwrap(wrapped)
548-
549-
expect(wrapped(1)).to.equal(1)
550-
})
551-
552-
it('should unwrap a constructor', () => {
553-
const Counter = function (start) {
554-
this.value = start
555-
}
556-
557-
const WrappedCounter = shimmer.wrapFunction(Counter, Counter => function (...args) {
558-
Counter.apply(this, arguments)
559-
this.value++
560-
})
561-
562-
shimmer.unwrap(WrappedCounter)
563-
564-
const counter = new WrappedCounter(1)
565-
566-
expect(counter.value).to.equal(1)
567-
expect(counter).to.be.an.instanceof(Counter)
568-
})
569-
570504
it('should mass wrap methods on objects', () => {
571505
const foo = {
572506
a: () => 'original',
@@ -586,44 +520,12 @@ describe('shimmer', () => {
586520
expect(bar.b()).to.equal('wrapped')
587521
})
588522

589-
it('should mass wrap methods on objects', () => {
590-
const foo = {
591-
a: () => 'original',
592-
b: () => 'original'
593-
}
594-
595-
const bar = {
596-
a: () => 'original',
597-
b: () => 'original'
598-
}
599-
600-
shimmer.massWrap([foo, bar], ['a', 'b'], () => () => 'wrapped')
601-
shimmer.massUnwrap([foo, bar], ['a', 'b'])
602-
603-
expect(foo.a()).to.equal('original')
604-
expect(foo.b()).to.equal('original')
605-
expect(bar.a()).to.equal('original')
606-
expect(bar.b()).to.equal('original')
607-
})
608-
609523
it('should validate that the function wrapper exists', () => {
610524
expect(() => shimmer.wrap(() => {})).to.throw()
611525
})
612526

613527
it('should validate that the function wrapper is a function', () => {
614528
expect(() => shimmer.wrap(() => {}, 'a')).to.throw()
615529
})
616-
617-
it('should never throw when unwrapping', () => {
618-
expect(() => shimmer.unwrap(() => {})).to.not.throw()
619-
})
620-
621-
it('should not throw when unwrapping an invalid type', () => {
622-
expect(() => shimmer.unwrap('foo')).to.not.throw()
623-
})
624-
625-
it('should not throw when unwrapping a function that was not wrapped', () => {
626-
expect(() => shimmer.unwrap(() => {})).to.not.throw()
627-
})
628530
})
629531
})

packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const { LOG_MESSAGE, REWRITTEN_MESSAGE } = require('./constants')
1515

1616
const hardcodedSecretCh = dc.channel('datadog:secrets:result')
1717
let rewriter
18+
let unwrapCompile = () => {}
1819
let getPrepareStackTrace, cacheRewrittenSourceMap
1920
let kSymbolPrepareStackTrace
2021
let esmRewriterEnabled = false
@@ -90,7 +91,8 @@ function getPrepareStackTraceAccessor () {
9091

9192
function getCompileMethodFn (compileMethod) {
9293
const rewriteFn = getRewriteFunction(rewriter)
93-
return function (content, filename) {
94+
95+
let delegate = function (content, filename) {
9496
try {
9597
if (isPrivateModule(filename) && isNotLibraryFile(filename)) {
9698
const rewritten = rewriteFn(content, filename)
@@ -108,6 +110,16 @@ function getCompileMethodFn (compileMethod) {
108110
}
109111
return compileMethod.apply(this, [content, filename])
110112
}
113+
114+
const shim = function () {
115+
return delegate.apply(this, arguments)
116+
}
117+
118+
unwrapCompile = function () {
119+
delegate = compileMethod
120+
}
121+
122+
return shim
111123
}
112124

113125
function esmRewritePostProcess (rewritten, filename) {
@@ -198,7 +210,7 @@ function enableEsmRewriter (telemetryVerbosity) {
198210
}
199211

200212
function disableRewriter () {
201-
shimmer.unwrap(Module.prototype, '_compile')
213+
unwrapCompile()
202214

203215
if (!Error.prepareStackTrace?.[kSymbolPrepareStackTrace]) return
204216

packages/dd-trace/test/appsec/iast/taint-tracking/rewriter.spec.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,8 @@ describe('IAST Rewriter', () => {
107107
rewriter.disableRewriter()
108108
})
109109

110-
it('Should unwrap module compile method on taint tracking disable', () => {
111-
rewriter.disableRewriter()
112-
113-
expect(shimmer.unwrap).to.be.calledOnce
114-
expect(shimmer.unwrap.getCall(0).args[1]).eq('_compile')
115-
})
110+
// TODO: This cannot be tested with mocking.
111+
it('Should unwrap module compile method on taint tracking disable') // eslint-disable-line mocha/no-pending-tests
116112

117113
it('Should keep original prepareStackTrace fn when calling enable and then disable', () => {
118114
const orig = Error.prepareStackTrace

0 commit comments

Comments
 (0)