即使我告诉 libzip 不要释放 libzip zip_source_t 缓冲区
libzip zip_source_t buffer is freed even tho I told libzip not to
我遇到了 libzip 问题,我不知道是不是我做错了什么,是不是库中的错误。
首先,我用 zip_source_buffer_create()
从磁盘上的 zip 文件创建一个存档(不要问我为什么不直接打开文件)。
我将 freep
标志设置为 0,这应该意味着我将处理释放自己的缓冲区,这不是 lipzip 的工作。
如果我不向存档中添加文件,它会起作用。
如果我将文件添加到存档中,当我删除缓冲区时,libzip 已经释放了它,我的应用程序崩溃了。这是库中的错误吗?
我写了这个不言自明的 mcve。使用 AUTO_FREE_BUF=0
和 ADD_FILE=1
,应用程序崩溃。每隔 (3) 个案例都有效。
libzip 版本:1.7.3
#include <zip.h>
#include <string>
#include <filesystem>
#include <fstream>
#include <iostream>
#define AUTO_FREE_BUF 0 //1-0
#define ADD_FILE 1 //1-0
int main(int argc, char** argv) {
const std::string add_file = "file.txt";
const std::string zip_file = "zipfile.zip";
size_t sz = std::filesystem::file_size(zip_file);
char* buf = new char[sz];
{
std::ifstream ifs{ zip_file, std::ios::binary };
ifs.read(buf, sz);
ifs.close();
zip_error_t ze;
zip_error_init(&ze);
zip_source_t* zs = zip_source_buffer_create(buf, sz, AUTO_FREE_BUF, &ze);
if (zs == nullptr) {
zip_error_fini(&ze);
return -1;
}
zip_error_init(&ze);
zip_t* z = zip_open_from_source(zs, NULL, &ze);
if (z == nullptr) {
zip_error_fini(&ze);
return -1;
}
#if ADD_FILE == 1
//add file
{
zip_source_t* file = zip_source_file(z, add_file.c_str(), 0, -1);
if (file == nullptr)
return -1;
zip_int64_t add = zip_file_add(z, add_file.c_str(), file, ZIP_FL_ENC_GUESS);
if (add == -1)
return -1;
}
#endif
zip_error_fini(&ze);
zip_source_keep(zs);
int close = zip_close(z);
if (close == -1)
return -1;
//write back archive to disk
//..
#if AUTO_FREE_BUF == 1
zip_source_free(zs);
#else
zip_source_free(zs); //<-is supposed to NOT free the buffer (with freep=0) but sometimes does
delete[] buf;
#endif
}
return 0;
}
经过(现在几个小时)的调查,我想我理解了这背后的基本原理,我认为 libzip 没有正常运行。
zip_source_free(src)
减少 src
的引用计数,如果它达到 0,则 src
对象被释放。此外,如果 src
是使用 freep=1
创建的,则关联的数据缓冲区也会被释放。如果 freep=0
则不应释放数据缓冲区。
但在这种情况下和某些情况下,缓冲区是免费的,这可能是无意的。
在上面的 mcve 中,将文件添加到存档中会使 libzip 释放数据缓冲区,即使源是使用 freep=0
创建的。如果没有文件添加到存档中,则缓冲区不会按预期释放,我可以安全地 delete[]
它。
这不是我的问题的解决方案。添加文件后,我在 mcve 中注意到 src.zip_err=18 [Invalid argument]
,因此文件的添加方式可能有问题 - 我还没有发现它有什么问题。
我已经从源代码安装了 libzip(如 install.md 中所述)并修改了您的源代码。我添加了一个文本文件(带有“Hello world”)和一个包含一个文本文件的 zip 文件。
我没有收到错误。 (但是,zip 文件中没有添加任何内容,所以这也不对)
(忽略被注释掉的异常参数 :P )
#include <zip.h>
#include <exception>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
static constexpr auto add_file{"file.txt"};
static constexpr auto zip_file{"zipfile.zip"};
static constexpr auto AUTO_FREE_BUF{false}; //1-0
static constexpr auto ADD_FILE{true}; //1-0
class MsgException : public std::exception {
public:
MsgException(std::string message) : _message(message) {}
char const *what() const noexcept override { return _message.c_str(); }
private:
std::string const _message;
};
int main() {
std::cout << "Started main\n";
auto const sz = std::filesystem::file_size(zip_file);
auto *const buf = new char[sz];
{
std::ifstream ifs{zip_file, std::ios::binary};
ifs.read(buf, sz);
}
std::cout << "Zipfile read\n";
zip_error_t ze;
try {
zip_error_init(&ze);
auto *zs = zip_source_buffer_create(buf, sz, AUTO_FREE_BUF ? 1 : 0, &ze);
if (zs == nullptr) throw MsgException("Can't create source: %s." /*, zip_error_strerror(&ze)*/);
//zip_error_init(&ze);
auto *z = zip_open_from_source(zs, 0, &ze);
if (z == nullptr) throw MsgException("Can't open zip from source: %s." /*, zip_error_strerror(&ze)*/);
if (ADD_FILE) {
//add file
auto *file = zip_source_file(z, add_file, 0, -1);
if (file == nullptr) throw MsgException("Can't create data source from file '%s': %s." /*, add_file, zip_strerror(z)*/);
if (zip_file_add(z, add_file, file, ZIP_FL_ENC_GUESS) < 0) {
//? zip_source_free(file);
throw MsgException("Can't file to zip archive: %s." /*, zip_strerror(z)*/);
}
}
zip_source_keep(zs);
if (zip_close(z) < 0) throw MsgException("Can't close zip archive: %s." /*, zip_strerror(z)*/);
//write back archive to disk
//..
zip_source_free(zs); //<-is supposed to NOT free the buffer (with freep=0) but sometimes does
} catch (std::exception &e) {
std::cerr << "Program aborted with error: " << e.what() << '\n';
}
zip_error_fini(&ze);
if (!AUTO_FREE_BUF) delete[] buf;
std::cout << "Finished main\n";
return 0;
}
构建使用
g++ -std=c++17 main.cpp -lzip -o main
编辑:添加了一些 RAII
#include <zip.h>
#include <exception>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
static constexpr auto add_file{ "file.txt" };
static constexpr auto zip_file{ "zipfile.zip" };
static constexpr auto AUTO_FREE_BUF{ false }; //1-0
static constexpr auto ADD_FILE{ true }; //1-0
class MsgException : public std::exception {
public:
MsgException(std::string message) : _message(message) {}
char const* what() const noexcept override { return _message.c_str(); }
private:
std::string const _message;
};
//RAII
class ZipError {
public:
ZipError() { zip_error_init(&ze); }
~ZipError() { zip_error_fini(&ze); }
zip_error* operator&() { return &ze; }
// actually probably need to delete copy/move constructor/assignment etc...
private:
zip_error_t ze;
};
int main() {
std::cout << "Started main\n";
std::vector<char> buf(std::filesystem::file_size(zip_file)); // RAII
{
std::ifstream ifs{ zip_file, std::ios::binary };
ifs.read(buf.data(), buf.size());
}
std::cout << "Zipfile read\n";
try {
ZipError ze;
auto* zs = zip_source_buffer_create(buf.data(), buf.size(), AUTO_FREE_BUF ? 1 : 0, &ze);
if (zs == nullptr) throw MsgException("Can't create source: %s." /*, zip_error_strerror(&ze)*/);
//zip_error_init(&ze);
auto* z = zip_open_from_source(zs, 0, &ze);
if (z == nullptr) throw MsgException("Can't open zip from source: %s." /*, zip_error_strerror(&ze)*/);
if (ADD_FILE) {
//add file
auto* file = zip_source_file(z, add_file, 0, -1);
if (file == nullptr) throw MsgException("Can't create data source from file '%s': %s." /*, add_file, zip_strerror(z)*/);
if (zip_file_add(z, add_file, file, ZIP_FL_ENC_GUESS) < 0) {
//? zip_source_free(file);
throw MsgException("Can't file to zip archive: %s." /*, zip_strerror(z)*/);
}
}
zip_source_keep(zs);
if (zip_close(z) < 0) throw MsgException("Can't close zip archive: %s." /*, zip_strerror(z)*/);
//write back archive to disk
//..
zip_source_free(zs); //<-is supposed to NOT free the buffer (with freep=0) but sometimes does
}
catch (std::exception& e) {
std::cerr << "Program aborted with error: " << e.what() << '\n';
}
std::cout << "Finished main\n";
return 0;
}
不要使用 libzip 处理使用 WinRar 创建的 zip 压缩文件......(使用 libzip 创建它们)
我遇到了 libzip 问题,我不知道是不是我做错了什么,是不是库中的错误。
首先,我用 zip_source_buffer_create()
从磁盘上的 zip 文件创建一个存档(不要问我为什么不直接打开文件)。
我将 freep
标志设置为 0,这应该意味着我将处理释放自己的缓冲区,这不是 lipzip 的工作。
如果我不向存档中添加文件,它会起作用。
如果我将文件添加到存档中,当我删除缓冲区时,libzip 已经释放了它,我的应用程序崩溃了。这是库中的错误吗?
我写了这个不言自明的 mcve。使用 AUTO_FREE_BUF=0
和 ADD_FILE=1
,应用程序崩溃。每隔 (3) 个案例都有效。
libzip 版本:1.7.3
#include <zip.h>
#include <string>
#include <filesystem>
#include <fstream>
#include <iostream>
#define AUTO_FREE_BUF 0 //1-0
#define ADD_FILE 1 //1-0
int main(int argc, char** argv) {
const std::string add_file = "file.txt";
const std::string zip_file = "zipfile.zip";
size_t sz = std::filesystem::file_size(zip_file);
char* buf = new char[sz];
{
std::ifstream ifs{ zip_file, std::ios::binary };
ifs.read(buf, sz);
ifs.close();
zip_error_t ze;
zip_error_init(&ze);
zip_source_t* zs = zip_source_buffer_create(buf, sz, AUTO_FREE_BUF, &ze);
if (zs == nullptr) {
zip_error_fini(&ze);
return -1;
}
zip_error_init(&ze);
zip_t* z = zip_open_from_source(zs, NULL, &ze);
if (z == nullptr) {
zip_error_fini(&ze);
return -1;
}
#if ADD_FILE == 1
//add file
{
zip_source_t* file = zip_source_file(z, add_file.c_str(), 0, -1);
if (file == nullptr)
return -1;
zip_int64_t add = zip_file_add(z, add_file.c_str(), file, ZIP_FL_ENC_GUESS);
if (add == -1)
return -1;
}
#endif
zip_error_fini(&ze);
zip_source_keep(zs);
int close = zip_close(z);
if (close == -1)
return -1;
//write back archive to disk
//..
#if AUTO_FREE_BUF == 1
zip_source_free(zs);
#else
zip_source_free(zs); //<-is supposed to NOT free the buffer (with freep=0) but sometimes does
delete[] buf;
#endif
}
return 0;
}
经过(现在几个小时)的调查,我想我理解了这背后的基本原理,我认为 libzip 没有正常运行。
zip_source_free(src)
减少 src
的引用计数,如果它达到 0,则 src
对象被释放。此外,如果 src
是使用 freep=1
创建的,则关联的数据缓冲区也会被释放。如果 freep=0
则不应释放数据缓冲区。
但在这种情况下和某些情况下,缓冲区是免费的,这可能是无意的。
在上面的 mcve 中,将文件添加到存档中会使 libzip 释放数据缓冲区,即使源是使用 freep=0
创建的。如果没有文件添加到存档中,则缓冲区不会按预期释放,我可以安全地 delete[]
它。
这不是我的问题的解决方案。添加文件后,我在 mcve 中注意到 src.zip_err=18 [Invalid argument]
,因此文件的添加方式可能有问题 - 我还没有发现它有什么问题。
我已经从源代码安装了 libzip(如 install.md 中所述)并修改了您的源代码。我添加了一个文本文件(带有“Hello world”)和一个包含一个文本文件的 zip 文件。
我没有收到错误。 (但是,zip 文件中没有添加任何内容,所以这也不对)
(忽略被注释掉的异常参数 :P )
#include <zip.h>
#include <exception>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
static constexpr auto add_file{"file.txt"};
static constexpr auto zip_file{"zipfile.zip"};
static constexpr auto AUTO_FREE_BUF{false}; //1-0
static constexpr auto ADD_FILE{true}; //1-0
class MsgException : public std::exception {
public:
MsgException(std::string message) : _message(message) {}
char const *what() const noexcept override { return _message.c_str(); }
private:
std::string const _message;
};
int main() {
std::cout << "Started main\n";
auto const sz = std::filesystem::file_size(zip_file);
auto *const buf = new char[sz];
{
std::ifstream ifs{zip_file, std::ios::binary};
ifs.read(buf, sz);
}
std::cout << "Zipfile read\n";
zip_error_t ze;
try {
zip_error_init(&ze);
auto *zs = zip_source_buffer_create(buf, sz, AUTO_FREE_BUF ? 1 : 0, &ze);
if (zs == nullptr) throw MsgException("Can't create source: %s." /*, zip_error_strerror(&ze)*/);
//zip_error_init(&ze);
auto *z = zip_open_from_source(zs, 0, &ze);
if (z == nullptr) throw MsgException("Can't open zip from source: %s." /*, zip_error_strerror(&ze)*/);
if (ADD_FILE) {
//add file
auto *file = zip_source_file(z, add_file, 0, -1);
if (file == nullptr) throw MsgException("Can't create data source from file '%s': %s." /*, add_file, zip_strerror(z)*/);
if (zip_file_add(z, add_file, file, ZIP_FL_ENC_GUESS) < 0) {
//? zip_source_free(file);
throw MsgException("Can't file to zip archive: %s." /*, zip_strerror(z)*/);
}
}
zip_source_keep(zs);
if (zip_close(z) < 0) throw MsgException("Can't close zip archive: %s." /*, zip_strerror(z)*/);
//write back archive to disk
//..
zip_source_free(zs); //<-is supposed to NOT free the buffer (with freep=0) but sometimes does
} catch (std::exception &e) {
std::cerr << "Program aborted with error: " << e.what() << '\n';
}
zip_error_fini(&ze);
if (!AUTO_FREE_BUF) delete[] buf;
std::cout << "Finished main\n";
return 0;
}
构建使用
g++ -std=c++17 main.cpp -lzip -o main
编辑:添加了一些 RAII
#include <zip.h>
#include <exception>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
static constexpr auto add_file{ "file.txt" };
static constexpr auto zip_file{ "zipfile.zip" };
static constexpr auto AUTO_FREE_BUF{ false }; //1-0
static constexpr auto ADD_FILE{ true }; //1-0
class MsgException : public std::exception {
public:
MsgException(std::string message) : _message(message) {}
char const* what() const noexcept override { return _message.c_str(); }
private:
std::string const _message;
};
//RAII
class ZipError {
public:
ZipError() { zip_error_init(&ze); }
~ZipError() { zip_error_fini(&ze); }
zip_error* operator&() { return &ze; }
// actually probably need to delete copy/move constructor/assignment etc...
private:
zip_error_t ze;
};
int main() {
std::cout << "Started main\n";
std::vector<char> buf(std::filesystem::file_size(zip_file)); // RAII
{
std::ifstream ifs{ zip_file, std::ios::binary };
ifs.read(buf.data(), buf.size());
}
std::cout << "Zipfile read\n";
try {
ZipError ze;
auto* zs = zip_source_buffer_create(buf.data(), buf.size(), AUTO_FREE_BUF ? 1 : 0, &ze);
if (zs == nullptr) throw MsgException("Can't create source: %s." /*, zip_error_strerror(&ze)*/);
//zip_error_init(&ze);
auto* z = zip_open_from_source(zs, 0, &ze);
if (z == nullptr) throw MsgException("Can't open zip from source: %s." /*, zip_error_strerror(&ze)*/);
if (ADD_FILE) {
//add file
auto* file = zip_source_file(z, add_file, 0, -1);
if (file == nullptr) throw MsgException("Can't create data source from file '%s': %s." /*, add_file, zip_strerror(z)*/);
if (zip_file_add(z, add_file, file, ZIP_FL_ENC_GUESS) < 0) {
//? zip_source_free(file);
throw MsgException("Can't file to zip archive: %s." /*, zip_strerror(z)*/);
}
}
zip_source_keep(zs);
if (zip_close(z) < 0) throw MsgException("Can't close zip archive: %s." /*, zip_strerror(z)*/);
//write back archive to disk
//..
zip_source_free(zs); //<-is supposed to NOT free the buffer (with freep=0) but sometimes does
}
catch (std::exception& e) {
std::cerr << "Program aborted with error: " << e.what() << '\n';
}
std::cout << "Finished main\n";
return 0;
}
不要使用 libzip 处理使用 WinRar 创建的 zip 压缩文件......(使用 libzip 创建它们)