Я использую libzip для обработки zip-файлов и основываю свой код на примере, найденном в ответе Родриго на этот вопрос. Вот его код, для быстрого ознакомления:
#include <zip.h>
int main()
{
//Open the ZIP archive
int err = 0;
zip *z = zip_open("foo.zip", 0, &err);
//Search for the file of given name
const char *name = "file.txt";
struct zip_stat st;
zip_stat_init(&st);
zip_stat(z, name, 0, &st);
//Alloc memory for its uncompressed contents
char *contents = new char[st.size];
//Read the compressed file
zip_file *f = zip_fopen(z, "file.txt", 0);
zip_fread(f, contents, st.size);
zip_fclose(f);
//And close the archive
zip_close(z);
}
Я проследил ошибки, которые я впоследствии получил от Valgrind, до этого кода — он жалуется на неинициализированное значение при открытии zip-файла «file.txt» с помощью «zip_fopen ()».
==29256== Conditional jump or move depends on uninitialised value(s)
==29256== at 0x5B4B290: inflateReset2 (in /usr/lib/libz.so.1.2.3.4)
==29256== by 0x5B4B37F: inflateInit2_ (in /usr/lib/libz.so.1.2.3.4)
==29256== by 0x4E2EB8C: zip_fopen_index (in /usr/lib/libzip.so.1.0.0)
==29256== by 0x400C32: main (main.cpp:24)
==29256== Uninitialised value was created by a heap allocation
==29256== at 0x4C244E8: malloc (vg_replace_malloc.c:236)
==29256== by 0x5B4B35B: inflateInit2_ (in /usr/lib/libz.so.1.2.3.4)
==29256== by 0x4E2EB8C: zip_fopen_index (in /usr/lib/libzip.so.1.0.0)
==29256== by 0x400C32: main (main.cpp:24)
==29256==
==29256==
==29256== HEAP SUMMARY:
==29256== in use at exit: 71 bytes in 1 blocks
==29256== total heap usage: 26 allocs, 25 frees, 85,851 bytes allocated
==29256==
==29256== 71 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29256== at 0x4C24A72: operator new[](unsigned long) (vg_replace_malloc.c:305)
==29256== by 0x400BEE: main (main.cpp:19)
Я не могу видеть, откуда исходит неинициализированное значение в этом коде. Кто-нибудь может отследить это, или ошибка кроется в самой libzip? Стоит ли переходить на другую zip-библиотеку, например, Minizip?
РЕДАКТИРОВАТЬ: 71 байт — это содержимое файла file.txt, который был прочитан в delete[] contents;
помеченный в конце, устранит это.
(Я бы оставил комментарий к первоначальному ответу, чтобы привлечь внимание к проблеме, но у меня нет нужного представителя.)
Вы заставили меня посмотреть 🙂
Да, это ошибка внутри zlib (используется libzip), так как и распределение, и использование памяти находятся внутри inflateInit2_
на тот же вызов. Ваш код даже не имеет возможности попасть в эту память.
Я могу повторить проблему, используя zlib 1.2.3, но в 1.2.7 она больше не отображается. У меня не было кода для 1.2.3, но если вы посмотрите на него, я бы проверил инициализацию state
и как это используется внутри inflateReset2
,
Редактировать: Выяснив проблему, я скачал исходный пакет Ubuntu для zlib (1.2.3.4), и строка обидела:
if (state->wbits != windowBits && state->window != Z_NULL) {
wbits
не инициализируется до этого и вызовет предупреждение. Странно то, что ни в оригинальном zlib 1.2.3, ни в 1.2.4 такой проблемы нет, похоже, это уникально для Ubuntu. 1.2.3 даже не имеет функции inflateReset2, а 1.2.4 — правильно;
if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
поскольку window
предварительно инициализируется в Z_NULL, неинициализированный wbits
читать не будет
Других решений пока нет …