为了阻止恶意用户发送超大报文,而导致int溢出或服务端为解析报文而分配大量内存致使内存耗尽,protobuf规定int溢出的默认值阈值是64MB(理论是512MB)。因此,当调用ParseFromString(str)方法时,若str的长度>64MB,返回会返回失败。
注意到protobuf中包含这样一个函数:void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold),其中有解释如下:
解决方法
LoadDBDataProtobuf::DocumentData pDocumentData; // LoadDBDataProtobuf::DocumentData为应用程序自定义的protobuf结构
::google::protobuf::io::ArrayInputStream input(strData.data(), strData.size()); //std::string strData,是响应报文中mTOM构造出而来
::google::protobuf::io::CodedInputStream decoder(&input);
decoder.SetTotalBytesLimit(1024 * 1024 * 1024, 64 * 1024 * 1024);
bool success = pDocumentData.ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
if (!success)
{
SvrResponse::instance()->setCurrentThreadReturnCode(eOtherErr, QString("protoBuf序列化出错"));
return false;
}
ZeroCopyInputStream 类
class LIBPROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream
{
public:
// 构造一个InputStream,返回data所指向的字节数组
// 若指定了block_size,则每次调用Next()返回不超过指定大小的数据块;否则,返回整个字节数组
ArrayInputStream(const void* data, int size, int block_size = -1);
~ArrayInputStream();
// implements ZeroCopyInputStream ----------------------------------
bool Next(const void** data, int* size);
......
}
CodedInputStream 类
class LIBPROTOBUF_EXPORT CodedInputStream
{
public:
// 构造一个从ZeroCopyInputStream读取数据的CodedInputStream对象
explicit CodedInputStream(ZeroCopyInputStream* input);
// total_bytes_limit:可读取的最大报文字节数
// warning_threshold:发出警告的最大报文字节数,若不为-1,则当读取的字节数超过warning_threshold后,stderr将会打印一条警告消息。
void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold)
// 当对报文进行解析后,必须调用ConsumedEntireMessage,以进一步判断报文是否被以正确方式读取完毕。
bool ConsumedEntireMessage()
......
}
ParseFromCodedStream(io::CodedInputStream* input)
功能:从给定的CodedInputStream对象中解析数据。
返回值:false,CodedInputStream格式错误或其他读错误。