@@ -103,9 +103,12 @@ pub const ParseLimits = struct {
103103 /// Maximum map size (default 1 million key-value pairs)
104104 max_map_size : usize = 1_000_000 ,
105105
106- /// Maximum string/binary data length (default 100MB)
106+ /// Maximum string data length (default 100MB)
107107 max_string_length : usize = 100 * 1024 * 1024 ,
108108
109+ /// Maximum binary data length (default 100MB)
110+ max_bin_length : usize = 100 * 1024 * 1024 ,
111+
109112 /// Maximum extension data length (default 100MB)
110113 max_ext_length : usize = 100 * 1024 * 1024 ,
111114};
@@ -1153,7 +1156,7 @@ pub fn PackWithLimits(
11531156 try self .writeTypeMarker (.ARRAY32 );
11541157 try self .writeU32Value (@as (u32 , @intCast (len )));
11551158 } else {
1156- return MsgPackError .MapLengthTooLong ;
1159+ return MsgPackError .ArrayLengthTooLong ;
11571160 }
11581161 for (arr ) | val | {
11591162 try self .write (val );
@@ -1509,22 +1512,31 @@ pub fn PackWithLimits(
15091512 }
15101513 }
15111514
1515+ inline fn validateBinLength (len : usize ) ! void {
1516+ if (len > parse_limits .max_bin_length ) {
1517+ return MsgPackError .BinDataLengthTooLong ;
1518+ }
1519+ }
1520+
15121521 fn readBin8Value (self : Self , allocator : Allocator ) ! []u8 {
15131522 const len = try self .readV8Value ();
1523+ try validateBinLength (len );
15141524 const bin = try self .readData (allocator , len );
15151525
15161526 return bin ;
15171527 }
15181528
15191529 fn readBin16Value (self : Self , allocator : Allocator ) ! []u8 {
15201530 const len = try self .readU16Value ();
1531+ try validateBinLength (len );
15211532 const bin = try self .readData (allocator , len );
15221533
15231534 return bin ;
15241535 }
15251536
15261537 fn readBin32Value (self : Self , allocator : Allocator ) ! []u8 {
15271538 const len = try self .readU32Value ();
1539+ try validateBinLength (len );
15281540 const bin = try self .readData (allocator , len );
15291541
15301542 return bin ;
@@ -1545,7 +1557,14 @@ pub fn PackWithLimits(
15451557 }
15461558 }
15471559
1560+ inline fn validateExtLength (len : usize ) ! void {
1561+ if (len > parse_limits .max_ext_length ) {
1562+ return MsgPackError .ExtDataTooLarge ;
1563+ }
1564+ }
1565+
15481566 inline fn readExtData (self : Self , allocator : Allocator , len : usize ) ! EXT {
1567+ try validateExtLength (len );
15491568 const ext_type = try self .readI8Value ();
15501569 const data = try self .readData (allocator , len );
15511570 return EXT {
@@ -1582,6 +1601,7 @@ pub fn PackWithLimits(
15821601
15831602 /// Read non-timestamp EXT data
15841603 inline fn readRegularExt (self : Self , ext_type : i8 , len : usize , allocator : Allocator ) ! Payload {
1604+ try validateExtLength (len );
15851605 const ext_data = try allocator .alloc (u8 , len );
15861606 errdefer allocator .free (ext_data );
15871607 _ = try self .readFrom (ext_data );
@@ -1612,6 +1632,13 @@ pub fn PackWithLimits(
16121632
16131633 /// Read timestamp payload based on marker
16141634 inline fn readTimestampPayload (self : Self , marker : Markers ) ! Payload {
1635+ const required_len : usize = switch (marker ) {
1636+ .FIXEXT4 = > FIXEXT4_LEN ,
1637+ .FIXEXT8 = > FIXEXT8_LEN ,
1638+ .EXT8 = > TIMESTAMP96_DATA_LEN ,
1639+ else = > unreachable ,
1640+ };
1641+ try validateExtLength (required_len );
16151642 const timestamp : Timestamp = switch (marker ) {
16161643 .FIXEXT4 = > try self .readTimestamp32 (),
16171644 .FIXEXT8 = > try self .readTimestamp64 (),
@@ -1844,7 +1871,7 @@ pub fn PackWithLimits(
18441871 const val = try self .readBinValue (marker , allocator );
18451872
18461873 // Validate binary length
1847- if (val .len > parse_limits .max_string_length ) {
1874+ if (val .len > parse_limits .max_bin_length ) {
18481875 allocator .free (val );
18491876 cleanupParseStack (& parse_stack , allocator );
18501877 return MsgPackError .BinDataLengthTooLong ;
@@ -1901,7 +1928,15 @@ pub fn PackWithLimits(
19011928 current_payload = Payload { .map = Map .init (allocator ) };
19021929 } else {
19031930 // Initialize map
1904- const map = Map .init (allocator );
1931+ var map = Map .init (allocator );
1932+ var map_owned = false ;
1933+ errdefer if (! map_owned ) map .deinit ();
1934+
1935+ const capacity = std .math .cast (u32 , len ) orelse {
1936+ cleanupParseStack (& parse_stack , allocator );
1937+ return MsgPackError .MapTooLarge ;
1938+ };
1939+ try map .ensureTotalCapacity (capacity );
19051940
19061941 // Push to stack
19071942 try appendToStack (& parse_stack , allocator , .{
@@ -1912,6 +1947,7 @@ pub fn PackWithLimits(
19121947 .remaining_pairs = len ,
19131948 } },
19141949 });
1950+ map_owned = true ;
19151951
19161952 needs_parent_fill = false ;
19171953 continue ; // Continue to read first key
0 commit comments