Search code examples
c++c++11libzip

libzip can't close file


I'm currently using libzip in a C++11 program to extract the contents of a compressed file and store them into a data structure that will also hold metadata related to the file.

I'm using the current method to explode the zip file and get the content of each file in it:

void explodeArchive(const string& path, vector<ZipFileModel>& files) {
    int error = 0;
    zip *zip = zip_open(path.c_str(), 0, &error);
    if (zip == nullptr) {
      throw logic_error("Could not extract content of file " + path);
    }
    const zip_int64_t n_entries = zip_get_num_entries(zip, ZIP_FL_UNCHANGED);
    for (zip_int64_t i = 0; i < n_entries; i++) {
      const char *file_name = zip_get_name(zip, i, ZIP_FL_ENC_GUESS);
      struct zip_stat st;
      zip_stat_init(&st);
      zip_stat(zip, file_name, ZIP_FL_NOCASE, &st);
      char *content = new char[st.size];
      std::cerr << file_name << std::endl;
      zip_file *file = zip_fopen(zip, file_name, ZIP_FL_NOCASE);
      const zip_int64_t did_read = zip_fread(file, content, st.size);
      if (did_read <= 0) {
        continue;
      }
      if (strlen(content) < st.size) {
        LOG(WARNING)<< "File " << file_name << " is truncated.";
      }
      if (strlen(content) > st.size) {
        content[st.size] = '\0';
      }

      ZipFileModel model;
      model.name = string(file_name);
      model.content = string(content);
      model.order = -1;
      files.push_back(model);

      zip_fclose(file);
      delete[] content;
    }
    zip_close(zip);
  }

My problem is that I get random segmentation faults with gdb pointing to zip_fclose(file);:

Program received signal SIGSEGV, Segmentation fault.
0x00000001001ef8a0 in zip_source_close (src=0x105001b00) at /Users/xxx/Projects/xxx/xxx/src/libzip/zip_source_close.c:48
48      (void)src->cb.l(src->src, src->ud, NULL, 0, ZIP_SOURCE_CLOSE);

What's the best way to debug this? As I said it happens intermittently so it's hard to pin down the exact cause.


Solution

  • You aren't closing the zip_file when there's nothing to read.

    First you open the file inside:

    zip_file *file = zip_fopen(zip, file_name, ZIP_FL_NOCASE);
    

    Then try to read something:

      const zip_int64_t did_read = zip_fread(file, content, st.size);
    

    and if there's nothing to read you continue and the file is never closed.

      if (did_read <= 0) {
        continue;
      }
    

    So, just add:

    if (did_read <= 0) {
        zip_fclose(file);
        continue;
    }