[THRIFT-5871] Improve MAX_MESSAGE_SIZE_CHECK and friends
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
index 9e80e10..0df2fb0 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.c
@@ -25,6 +25,14 @@
#include <thrift/c_glib/protocol/thrift_protocol.h>
#include <thrift/c_glib/protocol/thrift_binary_protocol.h>
+/* object properties */
+enum _ThriftBinaryProtocolProperties
+{
+ PROP_0,
+ PROP_THRIFT_BINARY_PROTOCOL_STRING_LIMIT,
+ PROP_THRIFT_BINARY_PROTOCOL_CONTAINER_LIMIT
+};
+
G_DEFINE_TYPE(ThriftBinaryProtocol, thrift_binary_protocol, THRIFT_TYPE_PROTOCOL)
static guint64
@@ -561,6 +569,14 @@
return -1;
}
+ ThriftBinaryProtocol *bp = THRIFT_BINARY_PROTOCOL (protocol);
+ if (bp->container_limit > 0 && sizei > bp->container_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", sizei, bp->container_limit);
+ return -1;
+ }
+
if(!ttc->checkReadBytesAvailable (THRIFT_TRANSPORT(tp->transport),
sizei * thrift_binary_protocol_get_min_serialized_size(protocol, k, error) +
sizei * thrift_binary_protocol_get_min_serialized_size(protocol, v, error),
@@ -618,6 +634,14 @@
return -1;
}
+ ThriftBinaryProtocol *bp = THRIFT_BINARY_PROTOCOL (protocol);
+ if (bp->container_limit > 0 && sizei > bp->container_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", sizei, bp->container_limit);
+ return -1;
+ }
+
if(!ttc->checkReadBytesAvailable (THRIFT_TRANSPORT(tp->transport),
(sizei * thrift_binary_protocol_get_min_serialized_size(protocol, e, error)),
error))
@@ -814,6 +838,23 @@
return -1;
}
+ ThriftBinaryProtocol *bp = THRIFT_BINARY_PROTOCOL (protocol);
+ if (bp->string_limit > 0 && read_len > bp->string_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", read_len, bp->string_limit);
+ *str = NULL;
+ return -1;
+ }
+
+ ThriftProtocol *tp = THRIFT_PROTOCOL (protocol);
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_GET_CLASS (tp->transport);
+ if(!ttc->checkReadBytesAvailable (THRIFT_TRANSPORT(tp->transport), read_len, error))
+ {
+ *str = NULL;
+ return -1;
+ }
+
/* allocate the memory for the string */
len = (guint32) read_len + 1; /* space for null terminator */
*str = g_new0 (gchar, len);
@@ -854,8 +895,36 @@
}
xfer += ret;
+ if (read_len < 0) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
+ "got negative size of %d", read_len);
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+
+ ThriftBinaryProtocol *bp = THRIFT_BINARY_PROTOCOL (protocol);
+ if (bp->string_limit > 0 && read_len > bp->string_limit) {
+ g_set_error (error, THRIFT_PROTOCOL_ERROR,
+ THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
+ "got size over limit (%d > %d)", read_len, bp->string_limit);
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+
if (read_len > 0)
{
+ ThriftProtocol *tp = THRIFT_PROTOCOL (protocol);
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_GET_CLASS (tp->transport);
+ if(!ttc->checkReadBytesAvailable (THRIFT_TRANSPORT(tp->transport), read_len, error))
+ {
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+
/* allocate the memory as an array of unsigned char for binary data */
*len = (guint32) read_len;
*buf = g_new (guchar, *len);
@@ -885,9 +954,9 @@
switch (type)
{
case T_STOP:
- return 0;
+ return 1; /* T_STOP needs to count itself */
case T_VOID:
- return 0;
+ return 1; /* T_VOID needs to count itself */
case T_BOOL:
return sizeof(gint8);
case T_BYTE:
@@ -903,7 +972,7 @@
case T_STRING:
return sizeof(int);
case T_STRUCT:
- return 0;
+ return 1; /* empty struct needs at least 1 byte for the T_STOP */
case T_MAP:
return sizeof(int);
case T_SET:
@@ -919,6 +988,48 @@
}
}
+/* property accessor */
+void
+thrift_binary_protocol_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ ThriftBinaryProtocol *tb;
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ tb = THRIFT_BINARY_PROTOCOL (object);
+
+ switch (property_id) {
+ case PROP_THRIFT_BINARY_PROTOCOL_STRING_LIMIT:
+ g_value_set_int (value, tb->string_limit);
+ break;
+ case PROP_THRIFT_BINARY_PROTOCOL_CONTAINER_LIMIT:
+ g_value_set_int (value, tb->container_limit);
+ break;
+ }
+}
+
+/* property mutator */
+void
+thrift_binary_protocol_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ ThriftBinaryProtocol *tb;
+
+ THRIFT_UNUSED_VAR (pspec);
+
+ tb = THRIFT_BINARY_PROTOCOL (object);
+
+ switch (property_id) {
+ case PROP_THRIFT_BINARY_PROTOCOL_STRING_LIMIT:
+ tb->string_limit = g_value_get_int (value);
+ break;
+ case PROP_THRIFT_BINARY_PROTOCOL_CONTAINER_LIMIT:
+ tb->container_limit = g_value_get_int (value);
+ break;
+ }
+}
+
static void
thrift_binary_protocol_init (ThriftBinaryProtocol *protocol)
{
@@ -929,7 +1040,39 @@
static void
thrift_binary_protocol_class_init (ThriftBinaryProtocolClass *klass)
{
- ThriftProtocolClass *cls = THRIFT_PROTOCOL_CLASS (klass);
+ ThriftProtocolClass *cls;
+ GObjectClass *gobject_class;
+ GParamSpec *param_spec;
+
+ cls = THRIFT_PROTOCOL_CLASS (klass);
+ gobject_class = G_OBJECT_CLASS (klass);
+ param_spec = NULL;
+
+ /* setup accessors and mutators */
+ gobject_class->get_property = thrift_binary_protocol_get_property;
+ gobject_class->set_property = thrift_binary_protocol_set_property;
+
+ param_spec = g_param_spec_int ("string_limit",
+ "Max allowed string size",
+ "Set the max string limit",
+ 0, /* min */
+ G_MAXINT32, /* max */
+ 0, /* default value */
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_BINARY_PROTOCOL_STRING_LIMIT,
+ param_spec);
+
+ param_spec = g_param_spec_int ("container_limit",
+ "Max allowed container size",
+ "Set the max container limit",
+ 0, /* min */
+ G_MAXINT32, /* max */
+ 0, /* default value */
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_BINARY_PROTOCOL_CONTAINER_LIMIT,
+ param_spec);
cls->write_message_begin = thrift_binary_protocol_write_message_begin;
cls->write_message_end = thrift_binary_protocol_write_message_end;
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.h b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.h
index bd8b84e..6d2bc3e 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.h
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_binary_protocol.h
@@ -52,6 +52,10 @@
struct _ThriftBinaryProtocol
{
ThriftProtocol parent;
+
+ /* protected */
+ gint32 string_limit;
+ gint32 container_limit;
};
typedef struct _ThriftBinaryProtocolClass ThriftBinaryProtocolClass;
diff --git a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
index 0aa9a6f..73be027 100644
--- a/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
+++ b/lib/c_glib/src/thrift/c_glib/protocol/thrift_compact_protocol.c
@@ -1414,6 +1414,13 @@
return -1;
}
+ ThriftProtocol *tp = THRIFT_PROTOCOL (protocol);
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_GET_CLASS (tp->transport);
+ if (read_len > 0 && !ttc->checkReadBytesAvailable (THRIFT_TRANSPORT (tp->transport), read_len, error)) {
+ *str = NULL;
+ return -1;
+ }
+
/* allocate the memory as an array of unsigned char for binary data */
*str = g_new0 (gchar, read_len + 1);
if (read_len > 0) {
@@ -1468,6 +1475,14 @@
}
if (read_len > 0) {
+ ThriftProtocol *tp = THRIFT_PROTOCOL (protocol);
+ ThriftTransportClass *ttc = THRIFT_TRANSPORT_GET_CLASS (tp->transport);
+ if (!ttc->checkReadBytesAvailable (THRIFT_TRANSPORT (tp->transport), read_len, error)) {
+ *buf = NULL;
+ *len = 0;
+ return -1;
+ }
+
/* allocate the memory as an array of unsigned char for binary data */
*len = (guint32) read_len;
*buf = g_new (guchar, *len);
@@ -1505,9 +1520,9 @@
switch (type)
{
case T_STOP:
- return 0;
+ return 1; /* T_STOP needs to count itself */
case T_VOID:
- return 0;
+ return 1; /* T_VOID needs to count itself */
case T_BOOL:
return sizeof(gint8);
case T_DOUBLE:
@@ -1523,7 +1538,7 @@
case T_STRING:
return sizeof(gint8);
case T_STRUCT:
- return 0;
+ return 1; /* empty struct needs at least 1 byte for the T_STOP */
case T_MAP:
return sizeof(gint8);
case T_SET:
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
index 9d3f25e..a03eb9e 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_transport.c
@@ -164,7 +164,7 @@
{
gboolean boolean = TRUE;
ThriftTransport *tt = THRIFT_TRANSPORT (transport);
- if(tt->remainingMessageSize_ < numBytes)
+ if(tt->remainingMessageSize_ < numBytes || numBytes < 0)
{
g_set_error(error,
THRIFT_TRANSPORT_ERROR,
diff --git a/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc b/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
index b227c33..67265cc 100644
--- a/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
+++ b/lib/cpp/src/thrift/protocol/TBinaryProtocol.tcc
@@ -469,6 +469,9 @@
return size;
}
+ // Check against MaxMessageSize before alloc
+ trans_->checkReadBytesAvailable(size);
+
str.resize(size);
this->trans_->readAll(reinterpret_cast<uint8_t*>(&str[0]), size);
return (uint32_t)size;
@@ -480,8 +483,8 @@
{
switch (type)
{
- case T_STOP: return 0;
- case T_VOID: return 0;
+ case T_STOP: return 1; // T_STOP needs to count itself
+ case T_VOID: return 1; // T_VOID needs to count itself
case T_BOOL: return sizeof(int8_t);
case T_BYTE: return sizeof(int8_t);
case T_DOUBLE: return sizeof(double);
@@ -489,7 +492,7 @@
case T_I32: return sizeof(int);
case T_I64: return sizeof(long);
case T_STRING: return sizeof(int); // string length
- case T_STRUCT: return 0; // empty struct
+ case T_STRUCT: return 1; // empty struct needs at least 1 byte for the T_STOP
case T_MAP: return sizeof(int); // element count
case T_SET: return sizeof(int); // element count
case T_LIST: return sizeof(int); // element count
diff --git a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
index b57568f..2a4990c 100644
--- a/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
+++ b/lib/cpp/src/thrift/protocol/TCompactProtocol.tcc
@@ -859,8 +859,8 @@
{
switch (type)
{
- case T_STOP: return 0;
- case T_VOID: return 0;
+ case T_STOP: return 1; // T_STOP needs to count itself
+ case T_VOID: return 1; // T_VOID needs to count itself
case T_BOOL: return sizeof(int8_t);
case T_DOUBLE: return 8; // uses fixedLongToBytes() which always writes 8 bytes
case T_BYTE: return sizeof(int8_t);
@@ -868,7 +868,7 @@
case T_I32: return sizeof(int8_t); // zigzag
case T_I64: return sizeof(int8_t); // zigzag
case T_STRING: return sizeof(int8_t); // string length
- case T_STRUCT: return 0; // empty struct
+ case T_STRUCT: return 1; // empty struct needs at least 1 byte for the T_STOP
case T_MAP: return sizeof(int8_t); // element count
case T_SET: return sizeof(int8_t); // element count
case T_LIST: return sizeof(int8_t); // element count
diff --git a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
index 1218190..a04d7ad 100644
--- a/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
+++ b/lib/cpp/src/thrift/protocol/TJSONProtocol.cpp
@@ -1131,8 +1131,8 @@
{
switch (type)
{
- case T_STOP: return 0;
- case T_VOID: return 0;
+ case T_STOP: return 1; // T_STOP needs to count itself
+ case T_VOID: return 1; // T_VOID needs to count itself
case T_BOOL: return 1; // written as int
case T_BYTE: return 1;
case T_DOUBLE: return 1;
diff --git a/lib/cpp/src/thrift/transport/TTransport.h b/lib/cpp/src/thrift/transport/TTransport.h
index 52b3a0a..1158bcf 100644
--- a/lib/cpp/src/thrift/transport/TTransport.h
+++ b/lib/cpp/src/thrift/transport/TTransport.h
@@ -274,7 +274,7 @@
*/
void checkReadBytesAvailable(long int numBytes)
{
- if (remainingMessageSize_ < numBytes)
+ if (remainingMessageSize_ < numBytes || numBytes < 0)
throw TTransportException(TTransportException::END_OF_FILE, "MaxMessageSize reached");
}
diff --git a/lib/delphi/src/Thrift.Protocol.Compact.pas b/lib/delphi/src/Thrift.Protocol.Compact.pas
index a8ad53a..afb3dd5 100644
--- a/lib/delphi/src/Thrift.Protocol.Compact.pas
+++ b/lib/delphi/src/Thrift.Protocol.Compact.pas
@@ -1011,8 +1011,8 @@
// Return the minimum number of bytes a type will consume on the wire
begin
case aType of
- TType.Stop: result := 0;
- TType.Void: result := 0;
+ TType.Stop: result := 1; // T_STOP needs to count itself
+ TType.Void: result := 1; // T_VOID needs to count itself
TType.Bool_: result := SizeOf(Byte);
TType.Byte_: result := SizeOf(Byte);
TType.Double_: result := 8; // uses fixedLongToBytes() which always writes 8 bytes
@@ -1020,7 +1020,7 @@
TType.I32: result := SizeOf(Byte);
TType.I64: result := SizeOf(Byte);
TType.String_: result := SizeOf(Byte); // string length
- TType.Struct: result := 0; // empty struct
+ TType.Struct: result := 1; // empty struct needs at least 1 byte for the T_STOP
TType.Map: result := SizeOf(Byte); // element count
TType.Set_: result := SizeOf(Byte); // element count
TType.List: result := SizeOf(Byte); // element count
diff --git a/lib/delphi/src/Thrift.Protocol.JSON.pas b/lib/delphi/src/Thrift.Protocol.JSON.pas
index 2a9682c..5be7ae0 100644
--- a/lib/delphi/src/Thrift.Protocol.JSON.pas
+++ b/lib/delphi/src/Thrift.Protocol.JSON.pas
@@ -1257,8 +1257,8 @@
// Return the minimum number of bytes a type will consume on the wire
begin
case aType of
- TType.Stop: result := 0;
- TType.Void: result := 0;
+ TType.Stop: result := 1; // T_STOP needs to count itself
+ TType.Void: result := 1; // T_VOID needs to count itself
TType.Bool_: result := 1;
TType.Byte_: result := 1;
TType.Double_: result := 1;
diff --git a/lib/delphi/src/Thrift.Protocol.pas b/lib/delphi/src/Thrift.Protocol.pas
index 969fbcd..ecf2103 100644
--- a/lib/delphi/src/Thrift.Protocol.pas
+++ b/lib/delphi/src/Thrift.Protocol.pas
@@ -1237,8 +1237,8 @@
// Return the minimum number of bytes a type will consume on the wire
begin
case aType of
- TType.Stop: result := 0;
- TType.Void: result := 0;
+ TType.Stop: result := 1; // T_STOP needs to count itself
+ TType.Void: result := 1; // T_VOID needs to count itself
TType.Bool_: result := SizeOf(Byte);
TType.Byte_: result := SizeOf(Byte);
TType.Double_: result := SizeOf(Double);
@@ -1246,7 +1246,7 @@
TType.I32: result := SizeOf(Int32);
TType.I64: result := SizeOf(Int64);
TType.String_: result := SizeOf(Int32); // string length
- TType.Struct: result := 0; // empty struct
+ TType.Struct: result := 1; // empty struct needs at least 1 byte for the T_STOP
TType.Map: result := SizeOf(Int32); // element count
TType.Set_: result := SizeOf(Int32); // element count
TType.List: result := SizeOf(Int32); // element count
diff --git a/lib/go/thrift/binary_protocol.go b/lib/go/thrift/binary_protocol.go
index eded931..431e446 100644
--- a/lib/go/thrift/binary_protocol.go
+++ b/lib/go/thrift/binary_protocol.go
@@ -355,7 +355,9 @@
err = NewTProtocolException(e)
return
}
- err = checkSizeForProtocol(size32, p.cfg)
+ minElemSize := p.getMinSerializedSize(kType) + p.getMinSerializedSize(vType)
+ totalMinSize := size32 * minElemSize
+ err = checkSizeForProtocol(totalMinSize, p.cfg)
if err != nil {
return
}
@@ -379,7 +381,9 @@
err = NewTProtocolException(e)
return
}
- err = checkSizeForProtocol(size32, p.cfg)
+ minElemSize := p.getMinSerializedSize(elemType)
+ totalMinSize := size32 * minElemSize
+ err = checkSizeForProtocol(totalMinSize, p.cfg)
if err != nil {
return
}
@@ -404,7 +408,9 @@
err = NewTProtocolException(e)
return
}
- err = checkSizeForProtocol(size32, p.cfg)
+ minElemSize := p.getMinSerializedSize(elemType)
+ totalMinSize := size32 * minElemSize
+ err = checkSizeForProtocol(totalMinSize, p.cfg)
if err != nil {
return
}
@@ -546,6 +552,44 @@
_ TConfigurationSetter = (*TBinaryProtocol)(nil)
)
+// Return the minimum number of bytes a type will consume on the wire
+func (p *TBinaryProtocol) getMinSerializedSize(ttype TType) int32 {
+ switch ttype {
+ case STOP:
+ return 1 // T_STOP needs to count itself
+ case VOID:
+ return 1 // T_VOID needs to count itsel∂
+ case BOOL:
+ return 1 // sizeof(int8)
+ case BYTE:
+ return 1 // sizeof(int8)
+ case DOUBLE:
+ return 8 // sizeof(double)
+ case I16:
+ return 2 // sizeof(short)
+ case I32:
+ return 4 // sizeof(int)
+ case I64:
+ return 8 // sizeof(long)
+ case STRING:
+ return 4 // string length
+ case STRUCT:
+ return 1 // empty struct needs at least 1 byte for the T_STOP
+ case MAP:
+ return 4 // element count
+ case SET:
+ return 4 // element count
+ case LIST:
+ return 4 // element count
+ case UUID:
+ return 16 // 16 bytes
+ default:
+ return 1 // unknown type
+ }
+}
+
+
+
// This function is shared between TBinaryProtocol and TCompactProtocol.
//
// It tries to read size bytes from trans, in a way that prevents large
diff --git a/lib/go/thrift/compact_protocol.go b/lib/go/thrift/compact_protocol.go
index 18915fe..a5223d3 100644
--- a/lib/go/thrift/compact_protocol.go
+++ b/lib/go/thrift/compact_protocol.go
@@ -486,10 +486,6 @@
err = NewTProtocolException(e)
return
}
- err = checkSizeForProtocol(size32, p.cfg)
- if err != nil {
- return
- }
size = int(size32)
keyAndValueType := byte(STOP)
@@ -501,6 +497,13 @@
}
keyType, _ = p.getTType(tCompactType(keyAndValueType >> 4))
valueType, _ = p.getTType(tCompactType(keyAndValueType & 0xf))
+
+ minElemSize := p.getMinSerializedSize(keyType) + p.getMinSerializedSize(valueType)
+ totalMinSize := size32 * minElemSize
+ err = checkSizeForProtocol(totalMinSize, p.cfg)
+ if err != nil {
+ return
+ }
return
}
@@ -524,15 +527,18 @@
}
size = int(size2)
}
- err = checkSizeForProtocol(int32(size), p.cfg)
- if err != nil {
- return
- }
elemType, e := p.getTType(tCompactType(size_and_type))
if e != nil {
err = NewTProtocolException(e)
return
}
+
+ minElemSize := p.getMinSerializedSize(elemType)
+ totalMinSize := int32(size) * minElemSize
+ err = checkSizeForProtocol(totalMinSize, p.cfg)
+ if err != nil {
+ return
+ }
return
}
@@ -860,6 +866,42 @@
p.cfg = conf
}
+// Return the minimum number of bytes a type will consume on the wire
+func (p *TCompactProtocol) getMinSerializedSize(ttype TType) int32 {
+ switch ttype {
+ case STOP:
+ return 1 // T_STOP needs to count itself
+ case VOID:
+ return 1 // T_VOID needs to count itself
+ case BOOL:
+ return 1 // sizeof(int8)
+ case BYTE:
+ return 1 // sizeof(int8)
+ case DOUBLE:
+ return 8 // uses PutUint64() which always writes 8 bytes
+ case I16:
+ return 1 // zigzag
+ case I32:
+ return 1 // zigzag
+ case I64:
+ return 1 // zigzag
+ case STRING:
+ return 1 // string length
+ case STRUCT:
+ return 1 // empty struct needs at least 1 byte for the T_STOP
+ case MAP:
+ return 1 // element count
+ case SET:
+ return 1 // element count
+ case LIST:
+ return 1 // element count
+ case UUID:
+ return 16 // 16 bytes
+ default:
+ return 1 // unknown type
+ }
+}
+
var (
_ TConfigurationSetter = (*TCompactProtocolFactory)(nil)
_ TConfigurationSetter = (*TCompactProtocol)(nil)
diff --git a/lib/go/thrift/json_protocol.go b/lib/go/thrift/json_protocol.go
index 6743a7f..3d53b69 100644
--- a/lib/go/thrift/json_protocol.go
+++ b/lib/go/thrift/json_protocol.go
@@ -314,11 +314,14 @@
if err != nil {
return keyType, valueType, size, err
}
- err = checkSizeForProtocol(int32(iSize), p.cfg)
+ size = int(iSize)
+
+ minElemSize := p.getMinSerializedSize(keyType) + p.getMinSerializedSize(valueType)
+ totalMinSize := int32(iSize) * minElemSize
+ err = checkSizeForProtocol(totalMinSize, p.cfg)
if err != nil {
return keyType, valueType, 0, err
}
- size = int(iSize)
_, e = p.ParseObjectStart()
return keyType, valueType, size, e
@@ -492,11 +495,14 @@
if err != nil {
return elemType, 0, err
}
- err = checkSizeForProtocol(int32(nSize), p.cfg)
+ size = int(nSize)
+
+ minElemSize := p.getMinSerializedSize(elemType)
+ totalMinSize := int32(nSize) * minElemSize
+ err = checkSizeForProtocol(totalMinSize, p.cfg)
if err != nil {
return elemType, 0, err
}
- size = int(nSize)
return elemType, size, nil
}
@@ -564,4 +570,40 @@
return TType(STOP), NewTProtocolExceptionWithType(INVALID_DATA, e)
}
+// Return the minimum number of bytes a type will consume on the wire
+func (p *TJSONProtocol) getMinSerializedSize(ttype TType) int32 {
+ switch ttype {
+ case STOP:
+ return 1 // T_STOP needs to count itself
+ case VOID:
+ return 1 // T_VOID needs to count itself
+ case BOOL:
+ return 1 // written as int
+ case BYTE:
+ return 1
+ case DOUBLE:
+ return 1
+ case I16:
+ return 1
+ case I32:
+ return 1
+ case I64:
+ return 1
+ case STRING:
+ return 2 // empty string
+ case STRUCT:
+ return 2 // empty struct
+ case MAP:
+ return 2 // empty map
+ case SET:
+ return 2 // empty set
+ case LIST:
+ return 2 // empty list
+ case UUID:
+ return 16 // empty UUID
+ default:
+ return 1 // unknown type
+ }
+}
+
var _ TConfigurationSetter = (*TJSONProtocol)(nil)
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
index 48b8d1e..c510895 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
@@ -321,8 +321,8 @@
{
switch (type)
{
- case TType.STOP: return 0;
- case TType.VOID_: return 0;
+ case TType.STOP: return 1; // T_STOP needs to count itself
+ case TType.VOID_: return 1; // T_VOID needs to count itself
case TType.BOOL: return 1;
case TType.BYTE: return 1;
case TType.DOUBLE: return 8;
@@ -330,7 +330,7 @@
case TType.I32: return 4;
case TType.I64: return 8;
case TType.STRING: return 4; // string length
- case TType.STRUCT: return 0; // empty struct
+ case TType.STRUCT: return 1; // empty struct needs at least 1 byte for the T_STOP
case TType.MAP: return 4; // element count
case TType.SET: return 4; // element count
case TType.LIST: return 4; // element count
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
index d3577f1..22af9e8 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
@@ -725,8 +725,8 @@
{
switch (type)
{
- case TType.STOP: return 0;
- case TType.VOID_: return 0;
+ case TType.STOP: return 1; // T_STOP needs to count itself
+ case TType.VOID_: return 1; // T_VOID needs to count itself
case TType.BOOL: return 1;
case TType.DOUBLE: return 8; // uses fixedLongToBytes() which always writes 8 bytes
case TType.BYTE: return 1;
@@ -734,7 +734,7 @@
case TType.I32: return 1; // zigzag
case TType.I64: return 1; // zigzag
case TType.STRING: return 1; // string length
- case TType.STRUCT: return 0; // empty struct
+ case TType.STRUCT: return 1; // empty struct needs at least 1 byte for the T_STOP
case TType.MAP: return 1; // element count
case TType.SET: return 1; // element count
case TType.LIST: return 1; // element count
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
index a47479d..4bbc427 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
@@ -792,8 +792,8 @@
{
switch (type)
{
- case TType.STOP: return 0;
- case TType.VOID_: return 0;
+ case TType.STOP: return 1; // T_STOP needs to count itself
+ case TType.VOID_: return 1; // T_VOID needs to count itself
case TType.BOOL: return 1; // written as int
case TType.BYTE: return 1;
case TType.DOUBLE: return 1;
diff --git a/lib/haxe/src/org/apache/thrift/transport/TEndpointTransport.hx b/lib/haxe/src/org/apache/thrift/transport/TEndpointTransport.hx
index b20dc70..fad3b54 100644
--- a/lib/haxe/src/org/apache/thrift/transport/TEndpointTransport.hx
+++ b/lib/haxe/src/org/apache/thrift/transport/TEndpointTransport.hx
@@ -78,7 +78,7 @@
// Throws if there are not enough bytes in the input stream to satisfy a read of numBytes bytes of data
public override function CheckReadBytesAvailable(numBytes : Int64) : Void
{
- if (RemainingMessageSize < numBytes)
+ if (RemainingMessageSize < numBytes || numBytes < 0)
throw new TTransportException(TTransportException.END_OF_FILE, 'CheckReadBytesAvailable(${numBytes}): MaxMessageSize reached, only ${RemainingMessageSize} bytes available');
}
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java
index 99c3e93..64d62b1 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java
@@ -524,9 +524,9 @@
public int getMinSerializedSize(byte type) throws TTransportException {
switch (type) {
case 0:
- return 0; // Stop
+ return 1; // Stop - T_STOP needs to count itself
case 1:
- return 0; // Void
+ return 1; // Void - T_VOID needs to count itself
case 2:
return 1; // Bool sizeof(byte)
case 3:
@@ -542,7 +542,7 @@
case 11:
return 4; // string length sizeof(int)
case 12:
- return 0; // empty struct
+ return 1; // empty struct needs at least 1 byte for the T_STOP
case 13:
return 4; // element count Map sizeof(int)
case 14:
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java
index abb5cca..3407f62 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java
@@ -911,9 +911,9 @@
public int getMinSerializedSize(byte type) throws TTransportException {
switch (type) {
case 0:
- return 0; // Stop
+ return 1; // Stop - T_STOP needs to count itself
case 1:
- return 0; // Void
+ return 1; // Void - T_VOID needs to count itself
case 2:
return 1; // Bool sizeof(byte)
case 3:
@@ -929,7 +929,7 @@
case 11:
return 1; // string length sizeof(byte)
case 12:
- return 0; // empty struct
+ return 1; // empty struct needs at least 1 byte for the T_STOP
case 13:
return 1; // element count Map sizeof(byte)
case 14:
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java
index 203c016..e32d70b 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java
@@ -972,9 +972,9 @@
public int getMinSerializedSize(byte type) throws TTransportException {
switch (type) {
case 0:
- return 0; // Stop
+ return 1; // Stop - T_STOP needs to count itself
case 1:
- return 0; // Void
+ return 1; // Void - T_VOID needs to count itself
case 2:
return 1; // Bool
case 3:
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java
index cceb517..7b78a65 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java
@@ -477,9 +477,9 @@
public int getMinSerializedSize(byte type) throws TException {
switch (type) {
case 0:
- return 0; // Stop
+ return 1; // Stop - T_STOP needs to count itself
case 1:
- return 0; // Void
+ return 1; // Void - T_VOID needs to count itself
case 2:
return 1; // Bool
case 3:
diff --git a/lib/java/src/main/java/org/apache/thrift/transport/TEndpointTransport.java b/lib/java/src/main/java/org/apache/thrift/transport/TEndpointTransport.java
index 6026390..99f3192 100644
--- a/lib/java/src/main/java/org/apache/thrift/transport/TEndpointTransport.java
+++ b/lib/java/src/main/java/org/apache/thrift/transport/TEndpointTransport.java
@@ -92,7 +92,7 @@
* @param numBytes
*/
public void checkReadBytesAvailable(long numBytes) throws TTransportException {
- if (remainingMessageSize < numBytes)
+ if (remainingMessageSize < numBytes || numBytes < 0)
throw new TTransportException(
TTransportException.MESSAGE_SIZE_LIMIT,
"Message size exceeds limit: " + getMaxMessageSize());
diff --git a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
index 44fa9f7..fc5be9a 100644
--- a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
@@ -452,8 +452,8 @@
{
switch (type)
{
- case TType.Stop: return 0;
- case TType.Void: return 0;
+ case TType.Stop: return 1; // T_STOP needs to count itself
+ case TType.Void: return 1; // T_VOID needs to count itself
case TType.Bool: return sizeof(byte);
case TType.Byte: return sizeof(byte);
case TType.Double: return sizeof(double);
@@ -461,7 +461,7 @@
case TType.I32: return sizeof(int);
case TType.I64: return sizeof(long);
case TType.String: return sizeof(int); // string length
- case TType.Struct: return 0; // empty struct
+ case TType.Struct: return 1; // empty struct needs at least 1 byte for the T_STOP
case TType.Map: return sizeof(int); // element count
case TType.Set: return sizeof(int); // element count
case TType.List: return sizeof(int); // element count
diff --git a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
index 1fd7e50..5ca4841 100644
--- a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
@@ -816,8 +816,8 @@
{
switch (type)
{
- case TType.Stop: return 0;
- case TType.Void: return 0;
+ case TType.Stop: return 1; // T_STOP needs to count itself
+ case TType.Void: return 1; // T_VOID needs to count itself
case TType.Bool: return sizeof(byte);
case TType.Double: return 8; // uses fixedLongToBytes() which always writes 8 bytes
case TType.Byte: return sizeof(byte);
@@ -825,7 +825,7 @@
case TType.I32: return sizeof(byte); // zigzag
case TType.I64: return sizeof(byte); // zigzag
case TType.String: return sizeof(byte); // string length
- case TType.Struct: return 0; // empty struct
+ case TType.Struct: return 1; // empty struct needs at least 1 byte for the T_STOP
case TType.Map: return sizeof(byte); // element count
case TType.Set: return sizeof(byte); // element count
case TType.List: return sizeof(byte); // element count
diff --git a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
index 170f294..37424a7 100644
--- a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
@@ -838,8 +838,8 @@
{
switch (type)
{
- case TType.Stop: return 0;
- case TType.Void: return 0;
+ case TType.Stop: return 1; // T_STOP needs to count itself
+ case TType.Void: return 1; // T_VOID needs to count itself
case TType.Bool: return 1; // written as int
case TType.Byte: return 1;
case TType.Double: return 1;