diff --git a/lib/std/json/static.zig b/lib/std/json/static.zig index d17723784279f5d7de669261000b4cb5580d67bf..fd140fc0f2325e25a6f83119e59c539007329442 100644 --- a/lib/std/json/static.zig +++ b/lib/std/json/static.zig @@ -32,6 +32,7 @@ pub const ParseOptions = struct { /// The default for `parseFromSlice` or `parseFromTokenSource` with a `*std.json.Scanner` input /// is the length of the input slice, which means `error.ValueTooLong` will never be returned. /// The default for `parseFromTokenSource` with a `*std.json.Reader` is `std.json.default_max_value_len`. + /// Ignored for values that don't need allocation or are not copied (see `allocate`). /// Ignored for `parseFromValue` and `parseFromValueLeaky`. max_value_len: ?usize = null, @@ -495,7 +496,7 @@ pub fn innerParse( if (ptrInfo.sentinel()) |s| { // Use our own array list so we can append the sentinel. var value_list = ArrayList(u8).init(allocator); - _ = try source.allocNextIntoArrayList(&value_list, .alloc_always); + _ = try source.allocNextIntoArrayListMax(&value_list, .alloc_always, options.max_value_len.?); return try value_list.toOwnedSliceSentinel(s); } if (ptrInfo.attrs.@"const") { diff --git a/lib/std/json/static_test.zig b/lib/std/json/static_test.zig index b9b89eae2b60e21734a9c28c3de689a43a740f16..0faf1b1804d6131fb45effd6ffbd80cf3e32ee25 100644 --- a/lib/std/json/static_test.zig +++ b/lib/std/json/static_test.zig @@ -772,7 +772,40 @@ test "parseFromTokenSource" { } test "max_value_len" { - try testing.expectError(error.ValueTooLong, parseFromSlice([]u8, testing.allocator, "\"0123456789\"", .{ .max_value_len = 5 })); + try testMaxValueLen([]u8, .alloc_if_needed); + try testMaxValueLen([]const u8, .alloc_always); + try testMaxValueLen([:0]u8, .alloc_if_needed); + try testMaxValueLen([:0]const u8, .alloc_if_needed); + + // If the value can be returned as a reference to the buffer, max_value_len doesn't apply. + { + const parsed = try parseFromSlice([]const u8, testing.allocator, "\"123\"", .{ .max_value_len = 1 }); + defer parsed.deinit(); + try testing.expectEqualStrings("123", parsed.value); + } + // If the value is returned as a number without needing intermediate allocations, max_value_len doesn't apply. + { + const parsed = try parseFromSlice(u32, testing.allocator, "\"001\"", .{ .max_value_len = 1 }); + defer parsed.deinit(); + try testing.expectEqual(1, parsed.value); + } +} + +fn testMaxValueLen(comptime T: type, when: Scanner.AllocWhen) !void { + const parsed = try parseFromSlice(T, testing.allocator, "\"12345\"", .{ + .max_value_len = 5, + .allocate = when, + }); + defer parsed.deinit(); + try testing.expectEqualStrings("12345", parsed.value); + + try testing.expectError( + error.ValueTooLong, + parseFromSlice(T, testing.allocator, "\"123456\"", .{ + .max_value_len = 5, + .allocate = when, + }), + ); } test "parse into vector" {