lib: suppress source map lookup exceptions

When the source map data are invalid json strings, skip construct
`SourceMap` on it. Additionally, suppress exceptions on source map
lookups and fix test runners crash on invalid source maps.

PR-URL: https://github.com/nodejs/node/pull/56299
Refs: https://github.com/nodejs/node/issues/56296
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com>
This commit is contained in:
Chengzhong Wu 2024-12-17 23:12:00 +00:00 committed by Antoine du Hamel
parent 990497c514
commit a33ec1248b
No known key found for this signature in database
GPG Key ID: 21D900FFDB233756
2 changed files with 42 additions and 11 deletions

View File

@ -155,6 +155,9 @@ function maybeCacheSourceMap(filename, content, moduleInstance, isGeneratedSourc
} }
const data = dataFromUrl(filename, sourceMapURL); const data = dataFromUrl(filename, sourceMapURL);
// `data` could be null if the source map is invalid.
// In this case, create a cache entry with null data with source url for test coverage.
const entry = { const entry = {
__proto__: null, __proto__: null,
lineLengths: lineLengths(content), lineLengths: lineLengths(content),
@ -277,6 +280,8 @@ function sourceMapFromDataUrl(sourceURL, url) {
const parsedData = JSONParse(decodedData); const parsedData = JSONParse(decodedData);
return sourcesToAbsolute(sourceURL, parsedData); return sourcesToAbsolute(sourceURL, parsedData);
} catch (err) { } catch (err) {
// TODO(legendecas): warn about invalid source map JSON string.
// But it could be verbose.
debug(err); debug(err);
return null; return null;
} }
@ -331,24 +336,38 @@ function sourceMapCacheToObject() {
/** /**
* Find a source map for a given actual source URL or path. * Find a source map for a given actual source URL or path.
*
* This function may be invoked from user code or test runner, this must not throw
* any exceptions.
* @param {string} sourceURL - actual source URL or path * @param {string} sourceURL - actual source URL or path
* @returns {import('internal/source_map/source_map').SourceMap | undefined} a source map or undefined if not found * @returns {import('internal/source_map/source_map').SourceMap | undefined} a source map or undefined if not found
*/ */
function findSourceMap(sourceURL) { function findSourceMap(sourceURL) {
if (RegExpPrototypeExec(kLeadingProtocol, sourceURL) === null) { if (typeof sourceURL !== 'string') {
sourceURL = pathToFileURL(sourceURL).href;
}
SourceMap ??= require('internal/source_map/source_map').SourceMap;
const entry = getModuleSourceMapCache().get(sourceURL) ?? generatedSourceMapCache.get(sourceURL);
if (entry === undefined) {
return undefined; return undefined;
} }
let sourceMap = entry.sourceMap;
if (sourceMap === undefined) { SourceMap ??= require('internal/source_map/source_map').SourceMap;
sourceMap = new SourceMap(entry.data, { lineLengths: entry.lineLengths }); try {
entry.sourceMap = sourceMap; if (RegExpPrototypeExec(kLeadingProtocol, sourceURL) === null) {
// If the sourceURL is an invalid path, this will throw an error.
sourceURL = pathToFileURL(sourceURL).href;
}
const entry = getModuleSourceMapCache().get(sourceURL) ?? generatedSourceMapCache.get(sourceURL);
if (entry?.data == null) {
return undefined;
}
let sourceMap = entry.sourceMap;
if (sourceMap === undefined) {
sourceMap = new SourceMap(entry.data, { lineLengths: entry.lineLengths });
entry.sourceMap = sourceMap;
}
return sourceMap;
} catch (err) {
debug(err);
return undefined;
} }
return sourceMap;
} }
module.exports = { module.exports = {

View File

@ -0,0 +1,12 @@
// Flags: --enable-source-maps
'use strict';
require('../common');
const test = require('node:test');
// Verify that test runner can handle invalid source maps.
test('ok', () => {});
// eslint-disable-next-line @stylistic/js/spaced-comment
//# sourceMappingURL=data:application/json;base64,-1