Skip to content

Commit aec37fa

Browse files
committed
Instantly bail out from the resolver on too long placeables
1 parent 13bc899 commit aec37fa

File tree

3 files changed

+18
-16
lines changed

3 files changed

+18
-16
lines changed

fluent/src/bundle.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {resolveComplexPattern} from "./resolver.js";
22
import FluentResource from "./resource.js";
3+
import { FluentNone } from "./types.js";
34

45
/**
56
* Message bundles are single-language stores of translations. They are
@@ -220,8 +221,13 @@ export default class FluentBundle {
220221
// Resolve a complex pattern.
221222
if (Array.isArray(pattern)) {
222223
let scope = this._createScope(args, errors);
223-
let value = resolveComplexPattern(scope, pattern);
224-
return value.toString(scope);
224+
try {
225+
let value = resolveComplexPattern(scope, pattern);
226+
return value.toString(scope);
227+
} catch (err) {
228+
scope.errors.push(err);
229+
return new FluentNone().toString(scope);
230+
}
225231
}
226232

227233
throw new TypeError("Invalid Pattern type");

fluent/src/resolver.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,15 @@ export function resolveComplexPattern(scope, ptn) {
283283
}
284284

285285
if (part.length > MAX_PLACEABLE_LENGTH) {
286-
scope.errors.push(
287-
new RangeError(
288-
"Too many characters in placeable " +
289-
`(${part.length}, max allowed is ${MAX_PLACEABLE_LENGTH})`
290-
)
291-
);
292286
scope.dirty.delete(ptn);
293-
return new FluentNone();
287+
// This is a fatal error which causes the resolver to instantly bail out
288+
// on this pattern. The length check protects against excessive memory
289+
// usage, and throwing protects against eating up the CPU when long
290+
// placeables are deeply nested.
291+
throw new RangeError(
292+
"Too many characters in placeable " +
293+
`(${part.length}, max allowed is ${MAX_PLACEABLE_LENGTH})`
294+
);
294295
}
295296

296297
result.push(part);

fluent/test/bomb_test.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ suite('Reference bombs', function() {
1313
});
1414

1515
suite('Billion Laughs', function(){
16-
this.timeout(10000);
17-
1816
suiteSetup(function() {
1917
bundle = new FluentBundle('en-US', { useIsolating: false });
2018
bundle.addMessages(ftl`
@@ -35,11 +33,8 @@ suite('Reference bombs', function() {
3533
test('does not expand all placeables', function() {
3634
const msg = bundle.getMessage('lolz');
3735
const val = bundle.formatPattern(msg.value, args, errs);
38-
assert.strictEqual(
39-
val,
40-
'{???} {???} {???} {???} {???} {???} {???} {???} {???} {???}'
41-
);
42-
assert.strictEqual(errs.length, 10010);
36+
assert.strictEqual(val, '{???}');
37+
assert.strictEqual(errs.length, 1);
4338
});
4439
});
4540
});

0 commit comments

Comments
 (0)