diff --git a/src/filters/misc.ts b/src/filters/misc.ts index a80dd6ece..57ed57812 100644 --- a/src/filters/misc.ts +++ b/src/filters/misc.ts @@ -9,19 +9,13 @@ function defaultFilter (this: FilterImpl, value: T1, def return isFalsy(value, this.context) ? defaultValue : value } -function json (this: FilterImpl, value: any, space = 0) { - const memoryLimit = this.context.memoryLimit - return JSON.stringify(value, (_key, val) => { - memoryLimit.use(typeof val === 'string' ? val.length : 1) - return val - }, space) +function json (value: any, space = 0) { + return JSON.stringify(value, null, space) } -function inspect (this: FilterImpl, value: any, space = 0) { - const memoryLimit = this.context.memoryLimit +function inspect (value: any, space = 0) { const ancestors: object[] = [] return JSON.stringify(value, function (this: unknown, _key: unknown, value: any) { - memoryLimit.use(typeof value === 'string' ? value.length : 1) if (typeof value !== 'object' || value === null) return value // `this` is the object that value is contained in, i.e., its direct parent. while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) ancestors.pop() diff --git a/src/filters/string.ts b/src/filters/string.ts index d0c59708e..f96d4b492 100644 --- a/src/filters/string.ts +++ b/src/filters/string.ts @@ -209,9 +209,7 @@ export function number_of_words (this: FilterImpl, input: string, mode?: 'cjk' | export function array_to_sentence_string (this: FilterImpl, array: unknown[], connector = 'and') { connector = stringify(connector) - let outputSize = connector.length + array.length * 2 - for (let i = 0; i < array.length; i++) outputSize += stringify(array[i]).length - this.context.memoryLimit.use(outputSize) + this.context.memoryLimit.use(array.length + connector.length) switch (array.length) { case 0: return '' diff --git a/test/integration/liquid/dos.spec.ts b/test/integration/liquid/dos.spec.ts index 3e072dda1..0ce9712d0 100644 --- a/test/integration/liquid/dos.spec.ts +++ b/test/integration/liquid/dos.spec.ts @@ -106,22 +106,6 @@ describe('DoS related', function () { expect(() => liquid.parseAndRenderSync('{{ array | array_to_sentence_string }}', { array })) .toThrow('memory alloc limit exceeded') }) - it('should charge json serialization of concat-doubled arrays', () => { - const liquid = new Liquid({ memoryLimit: 1e4 }) - const src = '{%- assign a = s | split: "NOSEP" -%}' + - '{%- assign a = a | concat: a -%}{%- assign a = a | concat: a -%}{%- assign a = a | concat: a -%}' + - '{{ a | json | size }}' - expect(() => liquid.parseAndRenderSync(src, { s: 'a'.repeat(5000) })) - .toThrow('memory alloc limit exceeded') - }) - it('should charge inspect serialization of concat-doubled arrays', () => { - const liquid = new Liquid({ memoryLimit: 1e4 }) - const src = '{%- assign a = s | split: "NOSEP" -%}' + - '{%- assign a = a | concat: a -%}{%- assign a = a | concat: a -%}{%- assign a = a | concat: a -%}' + - '{{ a | inspect | size }}' - expect(() => liquid.parseAndRenderSync(src, { s: 'a'.repeat(5000) })) - .toThrow('memory alloc limit exceeded') - }) it('should charge strip_html input length to memoryLimit', () => { const liquid = new Liquid({ memoryLimit: 100 }) expect(() => liquid.parseAndRenderSync('{{ s | strip_html }}', { s: 'a'.repeat(200) }))