Skip to content

Commit 5bea9d1

Browse files
authored
Merge pull request #395 from stasm/unskip-bomb
Bail out of Patterns with too long placeables
2 parents da30ec8 + aec37fa commit 5bea9d1

File tree

3 files changed

+20
-14
lines changed

3 files changed

+20
-14
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: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,17 +277,19 @@ export function resolveComplexPattern(scope, ptn) {
277277
}
278278

279279
if (part.length > MAX_PLACEABLE_LENGTH) {
280-
scope.errors.push(
281-
new RangeError(
282-
"Too many characters in placeable " +
283-
`(${part.length}, max allowed is ${MAX_PLACEABLE_LENGTH})`
284-
)
280+
scope.dirty.delete(ptn);
281+
// This is a fatal error which causes the resolver to instantly bail out
282+
// on this pattern. The length check protects against excessive memory
283+
// usage, and throwing protects against eating up the CPU when long
284+
// placeables are deeply nested.
285+
throw new RangeError(
286+
"Too many characters in placeable " +
287+
`(${part.length}, max allowed is ${MAX_PLACEABLE_LENGTH})`
285288
);
286-
result.push(part.slice(MAX_PLACEABLE_LENGTH));
287-
} else {
288-
result.push(part);
289289
}
290290

291+
result.push(part);
292+
291293
if (useIsolating) {
292294
result.push(PDI);
293295
}

fluent/test/bomb_test.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,10 @@ suite('Reference bombs', function() {
3030
`);
3131
});
3232

33-
// XXX Protect the FTL Resolver against the billion laughs attack
34-
// https://bugzil.la/1307126
35-
test.skip('does not expand all placeables', function() {
33+
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(val, '???');
36+
assert.strictEqual(val, '{???}');
3937
assert.strictEqual(errs.length, 1);
4038
});
4139
});

0 commit comments

Comments
 (0)