具有大数据长度的解压缩缓冲区崩溃
Unzip buffer with large data length is crashing
这是我用来解压缩缓冲区的函数。
string unzipBuffer(size_t decryptedLength, unsigned char * decryptedData)
{
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.avail_in = decryptedLength;
stream.next_in = (Bytef *)decryptedData;
stream.total_out = 0;
stream.avail_out = 0;
size_t dataLength = decryptedLength* 1.5;
char c[dataLength];
if (inflateInit2(&stream, 47) == Z_OK)
{
int status = Z_OK;
while (status == Z_OK)
{
if (stream.total_out >= dataLength)
{
dataLength += decryptedLength * 0.5;
}
stream.next_out = (Bytef *)c + stream.total_out;
stream.avail_out = (uint)(dataLength - stream.total_out);
status = inflate (&stream, Z_SYNC_FLUSH);
}
if (inflateEnd(&stream) == Z_OK)
{
if (status == Z_STREAM_END)
{
dataLength = stream.total_out;
}
}
}
std::string decryptedContentStr(c, c + dataLength);
return decryptedContentStr;
}
直到今天我才意识到它在这一行因大数据缓冲区(例如:decryptedLength:342792)而崩溃时一直运行良好:
status = inflate (&stream, Z_SYNC_FLUSH);
经过一两次迭代。谁能帮帮我?
如果您的代码通常可以正常工作,但无法处理大型数据集,那么这可能是由于堆栈溢出造成的,正如@StillLearning 在他的评论中所指出的那样。
通常(默认)堆栈大小为 1 MB。当你的 decryptedLength
为 342,792 时,你尝试在以下行中分配 514,188 字节:
char c[dataLength];
连同代码中的其他分配(最后在 inflate()
函数中),这可能已经太多了。要克服这个问题,您应该动态分配内存:
char* c = new char[dataLength];
如果你这样做,那么请不要忘记在你的 unzipBuffer()
函数结束时释放分配的内存:
delete[] c;
如果忘记删除已分配的内存,就会发生内存泄漏。
如果这不能(完全)解决您的问题,您仍然应该这样做,因为对于更大的数据集,由于堆栈的大小有限,您的代码肯定会中断。
如果您需要 "reallocate" 在 while()
循环中动态分配缓冲区,请查看 this Q&A。基本上您需要使用 new
、std::copy
和 delete[]
的组合。但是,如果将 char
数组替换为 std::vector<char>
甚至 std::vector<Bytef>
会更合适。然后,您可以使用 resize()
函数轻松扩大缓冲区。您可以使用 &my_vector[0]
直接访问 vector
的缓冲区,以便将其分配给 stream.next_out
.
c
不会因为你增加 datalength
而变大。您可能覆盖了 c
的末尾,因为您最初猜测压缩大小的 1.5 倍是错误的,从而导致了错误。
(这可能是此处另一个答案中建议的堆栈溢出,但我认为现在 8 MB 堆栈分配很常见。)
这是我用来解压缩缓冲区的函数。
string unzipBuffer(size_t decryptedLength, unsigned char * decryptedData)
{
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.avail_in = decryptedLength;
stream.next_in = (Bytef *)decryptedData;
stream.total_out = 0;
stream.avail_out = 0;
size_t dataLength = decryptedLength* 1.5;
char c[dataLength];
if (inflateInit2(&stream, 47) == Z_OK)
{
int status = Z_OK;
while (status == Z_OK)
{
if (stream.total_out >= dataLength)
{
dataLength += decryptedLength * 0.5;
}
stream.next_out = (Bytef *)c + stream.total_out;
stream.avail_out = (uint)(dataLength - stream.total_out);
status = inflate (&stream, Z_SYNC_FLUSH);
}
if (inflateEnd(&stream) == Z_OK)
{
if (status == Z_STREAM_END)
{
dataLength = stream.total_out;
}
}
}
std::string decryptedContentStr(c, c + dataLength);
return decryptedContentStr;
}
直到今天我才意识到它在这一行因大数据缓冲区(例如:decryptedLength:342792)而崩溃时一直运行良好:
status = inflate (&stream, Z_SYNC_FLUSH);
经过一两次迭代。谁能帮帮我?
如果您的代码通常可以正常工作,但无法处理大型数据集,那么这可能是由于堆栈溢出造成的,正如@StillLearning 在他的评论中所指出的那样。
通常(默认)堆栈大小为 1 MB。当你的 decryptedLength
为 342,792 时,你尝试在以下行中分配 514,188 字节:
char c[dataLength];
连同代码中的其他分配(最后在 inflate()
函数中),这可能已经太多了。要克服这个问题,您应该动态分配内存:
char* c = new char[dataLength];
如果你这样做,那么请不要忘记在你的 unzipBuffer()
函数结束时释放分配的内存:
delete[] c;
如果忘记删除已分配的内存,就会发生内存泄漏。
如果这不能(完全)解决您的问题,您仍然应该这样做,因为对于更大的数据集,由于堆栈的大小有限,您的代码肯定会中断。
如果您需要 "reallocate" 在 while()
循环中动态分配缓冲区,请查看 this Q&A。基本上您需要使用 new
、std::copy
和 delete[]
的组合。但是,如果将 char
数组替换为 std::vector<char>
甚至 std::vector<Bytef>
会更合适。然后,您可以使用 resize()
函数轻松扩大缓冲区。您可以使用 &my_vector[0]
直接访问 vector
的缓冲区,以便将其分配给 stream.next_out
.
c
不会因为你增加 datalength
而变大。您可能覆盖了 c
的末尾,因为您最初猜测压缩大小的 1.5 倍是错误的,从而导致了错误。
(这可能是此处另一个答案中建议的堆栈溢出,但我认为现在 8 MB 堆栈分配很常见。)