Skip to content

Commit 2ef9342

Browse files
janduboisclaude
andauthored
Fix panic and OOM in repeatString for large repeat counts (#2644)
The existing check (count > 10 million) does not account for string length. A 68-byte string repeated 35 trillion times passes the count check but panics in strings.Repeat with "makeslice: len out of range". Smaller counts (e.g. 10 million * 6-byte string = 60 MB) cause OOM on memory-constrained environments like OSS-Fuzz (2560 MB limit). Replace the count-only check with a result size check: the product of string length and repeat count must not exceed 10 MiB. Use division (len > limit/count) instead of multiplication (len*count > limit) to avoid integer overflow — a large count can wrap the product to a negative value, bypassing the guard entirely. Fixes at least four OSS-Fuzz bugs found via Lima's FuzzEvaluateExpression: https://issues.oss-fuzz.com/issues/418818862 (makeslice overflow) https://issues.oss-fuzz.com/issues/422001683 (timeout from huge alloc) https://issues.oss-fuzz.com/issues/383195001 (OOM, 3 GB allocation) https://issues.oss-fuzz.com/issues/385180606 (OOM, 97 TB allocation) Signed-off-by: Jan Dubois <jan@jandubois.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 17f66dc commit 2ef9342

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

pkg/yqlib/operator_multiply.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,10 @@ func repeatString(lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error
155155
return nil, err
156156
} else if count < 0 {
157157
return nil, fmt.Errorf("cannot repeat string by a negative number (%v)", count)
158-
} else if count > 10000000 {
159-
return nil, fmt.Errorf("cannot repeat string by more than 100 million (%v)", count)
158+
}
159+
maxResultLen := 10 * 1024 * 1024 // 10 MiB
160+
if count > 0 && len(stringNode.Value) > maxResultLen/count {
161+
return nil, fmt.Errorf("result of repeating string (%v bytes) by %v would exceed %v bytes", len(stringNode.Value), count, maxResultLen)
160162
}
161163
target.Value = strings.Repeat(stringNode.Value, count)
162164

pkg/yqlib/operator_multiply_test.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,11 @@ var multiplyOperatorScenarios = []expressionScenario{
237237
expectedError: "cannot repeat string by a negative number (-4)",
238238
},
239239
{
240-
description: "Multiply string X by more than 100 million",
241-
// very large string.repeats causes a panic
240+
description: "Multiply string by count that exceeds result size limit",
242241
skipDoc: true,
243242
document: `n: 100000001`,
244243
expression: `"banana" * .n`,
245-
expectedError: "cannot repeat string by more than 100 million (100000001)",
244+
expectedError: "result of repeating string (6 bytes) by 100000001 would exceed 10485760 bytes",
246245
},
247246
{
248247
description: "Multiply int node X string",
@@ -693,6 +692,27 @@ var multiplyOperatorScenarios = []expressionScenario{
693692
"D0, P[], (!!null)::null\n",
694693
},
695694
},
695+
{
696+
// Regression test for https://issues.oss-fuzz.com/issues/418818862
697+
// Large repeat count with a long string must not panic.
698+
skipDoc: true,
699+
expression: `"abc" * 99999999`,
700+
expectedError: "result of repeating string (3 bytes) by 99999999 would exceed 10485760 bytes",
701+
},
702+
{
703+
// Regression test for https://issues.oss-fuzz.com/issues/383195001
704+
// Product of string length * repeat count must be bounded.
705+
skipDoc: true,
706+
expression: `"x" * 99999999`,
707+
expectedError: "result of repeating string (1 bytes) by 99999999 would exceed 10485760 bytes",
708+
},
709+
{
710+
// The size guard must not overflow: len * count can wrap to
711+
// a negative or small value on 64-bit, bypassing the check.
712+
skipDoc: true,
713+
expression: `"ab" * 4611686018427387904`,
714+
expectedError: "result of repeating string (2 bytes) by 4611686018427387904 would exceed 10485760 bytes",
715+
},
696716
}
697717

698718
func TestMultiplyOperatorScenarios(t *testing.T) {

0 commit comments

Comments
 (0)