1
1
'use strict' ;
2
2
3
+ const {
4
+ JSON ,
5
+ Object : {
6
+ create : ObjectCreate ,
7
+ keys : ObjectKeys ,
8
+ getOwnPropertyDescriptor : ObjectGetOwnPropertyDescriptor ,
9
+ } ,
10
+ ObjectPrototype : {
11
+ hasOwnProperty : ObjectHasOwnProperty
12
+ } ,
13
+ MapPrototype : {
14
+ entries : MapEntries
15
+ } , uncurryThis
16
+ } = primordials ;
17
+
18
+ const MapIteratorNext = uncurryThis ( MapEntries ( new Map ( ) ) . next ) ;
19
+ const WeakMapGet = uncurryThis ( WeakMap . prototype . get ) ;
20
+
21
+ function ObjectGetValueSafe ( obj , key ) {
22
+ const desc = ObjectGetOwnPropertyDescriptor ( obj , key ) ;
23
+ return ObjectHasOwnProperty ( desc , 'value' ) ? desc . value : undefined ;
24
+ }
25
+
3
26
// See https://sourcemaps.info/spec.html for SourceMap V3 specification.
4
27
const { Buffer } = require ( 'buffer' ) ;
5
28
const debug = require ( 'internal/util/debuglog' ) . debuglog ( 'source_map' ) ;
@@ -9,14 +32,14 @@ const { getOptionValue } = require('internal/options');
9
32
const {
10
33
normalizeReferrerURL,
11
34
} = require ( 'internal/modules/cjs/helpers' ) ;
12
- const { JSON , Object } = primordials ;
13
35
// For cjs, since Module._cache is exposed to users, we use a WeakMap
14
36
// keyed on module, facilitating garbage collection.
15
37
const cjsSourceMapCache = new WeakMap ( ) ;
16
38
// The esm cache is not exposed to users, so we can use a Map keyed
17
39
// on filenames.
18
40
const esmSourceMapCache = new Map ( ) ;
19
41
const { fileURLToPath, URL } = require ( 'url' ) ;
42
+ let Module ;
20
43
21
44
let experimentalSourceMaps ;
22
45
function maybeCacheSourceMap ( filename , content , cjsModuleInstance ) {
@@ -40,6 +63,7 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance) {
40
63
const data = dataFromUrl ( basePath , match . groups . sourceMappingURL ) ;
41
64
const url = data ? null : match . groups . sourceMappingURL ;
42
65
if ( cjsModuleInstance ) {
66
+ if ( ! Module ) Module = require ( 'internal/modules/cjs/loader' ) . Module ;
43
67
cjsSourceMapCache . set ( cjsModuleInstance , {
44
68
filename,
45
69
lineLengths : lineLengths ( content ) ,
@@ -148,17 +172,27 @@ function rekeySourceMap(cjsModuleInstance, newInstance) {
148
172
}
149
173
}
150
174
175
+ // WARNING: The `sourceMapCacheToObject` and `appendCJSCache` run during
176
+ // shutdown. In particular, they also run when Workers are terminated, making
177
+ // it important that they do not call out to any user-provided code, including
178
+ // built-in prototypes that might have been tampered with.
179
+
151
180
// Get serialized representation of source-map cache, this is used
152
181
// to persist a cache of source-maps to disk when NODE_V8_COVERAGE is enabled.
153
182
function sourceMapCacheToObject ( ) {
154
- const obj = Object . create ( null ) ;
183
+ const obj = ObjectCreate ( null ) ;
155
184
156
- for ( const [ k , v ] of esmSourceMapCache ) {
185
+ const it = MapEntries ( esmSourceMapCache ) ;
186
+ let entry ;
187
+ while ( ! ( entry = MapIteratorNext ( it ) ) . done ) {
188
+ const k = entry . value [ 0 ] ;
189
+ const v = entry . value [ 1 ] ;
157
190
obj [ k ] = v ;
158
191
}
192
+
159
193
appendCJSCache ( obj ) ;
160
194
161
- if ( Object . keys ( obj ) . length === 0 ) {
195
+ if ( ObjectKeys ( obj ) . length === 0 ) {
162
196
return undefined ;
163
197
} else {
164
198
return obj ;
@@ -171,23 +205,28 @@ function sourceMapCacheToObject() {
171
205
// TODO(bcoe): this means we don't currently serialize source-maps attached
172
206
// to error instances, only module instances.
173
207
function appendCJSCache ( obj ) {
174
- const { Module } = require ( 'internal/modules/cjs/loader' ) ;
175
- Object . keys ( Module . _cache ) . forEach ( ( key ) => {
176
- const value = cjsSourceMapCache . get ( Module . _cache [ key ] ) ;
208
+ if ( ! Module ) return ;
209
+ const cjsModuleCache = ObjectGetValueSafe ( Module , '_cache' ) ;
210
+ const cjsModules = ObjectKeys ( cjsModuleCache ) ;
211
+ for ( let i = 0 ; i < cjsModules . length ; i ++ ) {
212
+ const key = cjsModules [ i ] ;
213
+ const module = ObjectGetValueSafe ( cjsModuleCache , key ) ;
214
+ const value = WeakMapGet ( cjsSourceMapCache , module ) ;
177
215
if ( value ) {
216
+ // This is okay because `obj` has a null prototype.
178
217
obj [ `file://${ key } ` ] = {
179
- lineLengths : value . lineLengths ,
180
- data : value . data ,
181
- url : value . url
218
+ lineLengths : ObjectGetValueSafe ( value , ' lineLengths' ) ,
219
+ data : ObjectGetValueSafe ( value , ' data' ) ,
220
+ url : ObjectGetValueSafe ( value , ' url' )
182
221
} ;
183
222
}
184
- } ) ;
223
+ }
185
224
}
186
225
187
226
// Attempt to lookup a source map, which is either attached to a file URI, or
188
227
// keyed on an error instance.
189
228
function findSourceMap ( uri , error ) {
190
- const { Module } = require ( 'internal/modules/cjs/loader' ) ;
229
+ if ( ! Module ) Module = require ( 'internal/modules/cjs/loader' ) . Module ;
191
230
let sourceMap = cjsSourceMapCache . get ( Module . _cache [ uri ] ) ;
192
231
if ( ! uri . startsWith ( 'file://' ) ) uri = normalizeReferrerURL ( uri ) ;
193
232
if ( sourceMap === undefined ) {
0 commit comments