引言
我在代码中使用下面的代码进行Gzip压缩,并在非常特定的条件下体验代码分段错误。我试着自己解决这个问题后,基本上完全迷失了方向。
代码是由以下配置生成的:
在配置1-3中,对压缩代码的测试调用成功.在配置4中,当从Qt创建者IDE中启动时,对压缩代码的测试调用就会成功。在配置4中,当从Power命令行生成时,对压缩代码的测试调用会导致一个分段错误,如: 1.在power中设置与Qt使用的环境变量相同的environment.ACLineStatus 2。调用与Qt中为MinGw-x86-64配置配置的Qt中配置的完全相同的命令。
当我试图为MSVC和MinGw使用32768的缓冲区大小时,即使在qt创建者内部调用测试时,我也可以在该特定行再现类似的崩溃。MSVC以16384崩溃,MinGw崩溃为32768,因此在我的代码中为缓冲区大小提供了下面的#ifdef。
问题
我做了混合构建(在IDE中调用测试表单的QT创建者构建,以及从命令行调用测试的手动cli构建),以便在只安装了QT的干净虚拟机上测试行为,在启动任何构建之前具有完全相同和干净的环境。
分段错误的代码
#define BASE2_ZLIB_WINDOWSIZE 15
#define GZIP_ZLIB_WINDOWSIZE (16 + BASE2_ZLIB_WINDOWSIZE)
#define MOD_GZIP_ZLIB_CFACTOR 9
#define MOD_GZIP_ZLIB_BSIZE 8096
#ifdef _MSC_VER
#define COMPR_BUFFER_SIZE 32768
#else
#define COMPR_BUFFER_SIZE 16384
#endif
QByteArray gzipCompress(QByteArray data, int compressionlevel)
{
char buffer[COMPR_BUFFER_SIZE];
z_stream cmpr_stream;
cmpr_stream.next_in = reinterpret_cast<unsigned char *>(data.data());
cmpr_stream.avail_in = static_cast<uInt>(data.size());
cmpr_stream.total_in = 0;
cmpr_stream.total_out = 0;
cmpr_stream.zalloc = Z_NULL;
cmpr_stream.zalloc = Z_NULL;
QByteArray compressed;
// the actual compression work.
if (deflateInit2(&cmpr_stream, compressionlevel, Z_DEFLATED, GZIP_ZLIB_WINDOWSIZE, MOD_GZIP_ZLIB_CFACTOR,
Z_DEFAULT_STRATEGY) != Z_OK)
{
return compressed;
}
// retrieve the compressed bytes blockwise
int ret;
do
{
cmpr_stream.next_out = reinterpret_cast<uint8_t *>(buffer);
cmpr_stream.avail_out = COMPR_BUFFER_SIZE;
ret = deflate(&cmpr_stream, Z_FINISH);
if (static_cast<unsigned long>(compressed.size()) < cmpr_stream.total_out)
{
// append the block to the output string
compressed.append(buffer, static_cast<int>(cmpr_stream.total_out) - compressed.size());
}
} while (ret == Z_OK);
deflateEnd(&cmpr_stream);
if (ret != Z_STREAM_END)
{
return QByteArray();
}
return compressed;
}测试,调用代码
TEST(Compression, gzipSuccessfull)
{
QString string_data(
"Complex Test 256/n Data complete Lorem ipsum dolor sit amet, consetetur sadipscing elitr "
"Lorem ipsum dolor sit amet, consetetur sadipscing elitr");
QByteArray raw = string_data.toLatin1();
qDebug() << "Orig size: " << raw.size();
// Crashes in the next line
QByteArray compressed = gzipCompress(raw);
qDebug() << "Compressed size: " << compressed.size();
QByteArray uncompressed = gzipDecompress(compressed);
qDebug() << "Uncompressed size: " << uncompressed.size();
QString restored = QString::fromLatin1(uncompressed);
ASSERT_TRUE(string_data == restored);
}发布于 2020-10-22 15:39:03
不确定这是否是导致分段错误的原因,但您需要初始化zfree。它看起来像是代码中的复制/粘贴错误,因为您已经初始化了两次zalloc。应:
cmpr_stream.zalloc = Z_NULL;
cmpr_stream.zfree = Z_NULL;并完成:
cmpr_stream.opaque = Z_NULL;关于附加多少的计算看起来是正确的,但这是一种迂回的方法,如果long为32位,则可能会出现可移植性问题。在这种情况下,当超过4GB时,total_out不会表示出总数。相反,您应该直接使用deflate()的结果
if (cmpr_stream.avail_out < COMPR_BUFFER_SIZE)
{
// append the block to the output string
compressed.append(buffer, COMPR_BUFFER_SIZE - cmpr_stream.avail_out);
}由于append的参数是int而不是unsigned,所以您应该确保COMPR_BUFFER_SIZE适合于int。
https://stackoverflow.com/questions/64483407
复制相似问题