11'use strict' ;
22
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+
326// See https://sourcemaps.info/spec.html for SourceMap V3 specification.
427const { Buffer } = require ( 'buffer' ) ;
528const debug = require ( 'internal/util/debuglog' ) . debuglog ( 'source_map' ) ;
@@ -9,14 +32,14 @@ const { getOptionValue } = require('internal/options');
932const {
1033 normalizeReferrerURL,
1134} = require ( 'internal/modules/cjs/helpers' ) ;
12- const { JSON , Object } = primordials ;
1335// For cjs, since Module._cache is exposed to users, we use a WeakMap
1436// keyed on module, facilitating garbage collection.
1537const cjsSourceMapCache = new WeakMap ( ) ;
1638// The esm cache is not exposed to users, so we can use a Map keyed
1739// on filenames.
1840const esmSourceMapCache = new Map ( ) ;
1941const { fileURLToPath, URL } = require ( 'url' ) ;
42+ let Module ;
2043
2144let experimentalSourceMaps ;
2245function maybeCacheSourceMap ( filename , content , cjsModuleInstance ) {
@@ -40,6 +63,7 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance) {
4063 const data = dataFromUrl ( basePath , match . groups . sourceMappingURL ) ;
4164 const url = data ? null : match . groups . sourceMappingURL ;
4265 if ( cjsModuleInstance ) {
66+ if ( ! Module ) Module = require ( 'internal/modules/cjs/loader' ) . Module ;
4367 cjsSourceMapCache . set ( cjsModuleInstance , {
4468 filename,
4569 lineLengths : lineLengths ( content ) ,
@@ -148,17 +172,27 @@ function rekeySourceMap(cjsModuleInstance, newInstance) {
148172 }
149173}
150174
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+
151180// Get serialized representation of source-map cache, this is used
152181// to persist a cache of source-maps to disk when NODE_V8_COVERAGE is enabled.
153182function sourceMapCacheToObject ( ) {
154- const obj = Object . create ( null ) ;
183+ const obj = ObjectCreate ( null ) ;
155184
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 ] ;
157190 obj [ k ] = v ;
158191 }
192+
159193 appendCJSCache ( obj ) ;
160194
161- if ( Object . keys ( obj ) . length === 0 ) {
195+ if ( ObjectKeys ( obj ) . length === 0 ) {
162196 return undefined ;
163197 } else {
164198 return obj ;
@@ -171,23 +205,28 @@ function sourceMapCacheToObject() {
171205// TODO(bcoe): this means we don't currently serialize source-maps attached
172206// to error instances, only module instances.
173207function 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 ) ;
177215 if ( value ) {
216+ // This is okay because `obj` has a null prototype.
178217 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' )
182221 } ;
183222 }
184- } ) ;
223+ }
185224}
186225
187226// Attempt to lookup a source map, which is either attached to a file URI, or
188227// keyed on an error instance.
189228function findSourceMap ( uri , error ) {
190- const { Module } = require ( 'internal/modules/cjs/loader' ) ;
229+ if ( ! Module ) Module = require ( 'internal/modules/cjs/loader' ) . Module ;
191230 let sourceMap = cjsSourceMapCache . get ( Module . _cache [ uri ] ) ;
192231 if ( ! uri . startsWith ( 'file://' ) ) uri = normalizeReferrerURL ( uri ) ;
193232 if ( sourceMap === undefined ) {
0 commit comments