Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: core dump with BitArchiveWriter #206

Closed
1 task done
gbook opened this issue May 3, 2024 · 9 comments
Closed
1 task done

[Bug]: core dump with BitArchiveWriter #206

gbook opened this issue May 3, 2024 · 9 comments
Assignees
Labels

Comments

@gbook
Copy link

gbook commented May 3, 2024

bit7z version

4.0.x

Compilation options

BIT7Z_AUTO_FORMAT

7-zip version

v23.01

7-zip shared library used

7z.dll / 7z.so

Compilers

GCC

Compiler versions

No response

Architecture

x86_64

Operating system

Linux

Operating system versions

RHEL 8

Bug description

The following code, specifically the BitArchiveWriter.compressTo() function,

    try {
        using namespace bit7z;
#ifdef Q_OS_WINDOWS
        Bit7zLibrary lib("C:/Program Files/7-Zip/7z.dll");
#else
        Bit7zLibrary lib("/usr/libexec/p7zip/7z.so");
#endif
        if (archivePath.endsWith(".zip", Qt::CaseInsensitive)) {
            BitArchiveWriter archive(lib, BitFormat::Zip);
            archive.setUpdateMode(UpdateMode::Update);
            archive.addDirectory(dir.toStdString());
            archive.compressTo(archivePath.toStdString());
        }
        else {
            BitArchiveWriter archive(lib, BitFormat::SevenZip);
            archive.setUpdateMode(UpdateMode::Update);
            archive.addDirectory(dir.toStdString());
            archive.compressTo(archivePath.toStdString()); /* <----- core dump ----- */
        }
        m = "Successfully compressed directory [" + dir + "] to archive [" + archivePath + "]";
        return true;
    }
    catch ( const bit7z::BitException& ex ) {
        /* Do something with ex.what()...*/
        m = "Unable to compress directory into archive using bit7z library [" + QString(ex.what()) + "]";
        return false;
    }

produces the following error at runtime

free(): double free detected in tcache 2
Aborted (core dumped)

Steps to reproduce

No response

Expected behavior

No response

Relevant compilation output

No response

Code of Conduct

@rikyoz
Copy link
Owner

rikyoz commented May 3, 2024

Hi!
I see from the code that you're using p7zip's 7z.so on Linux.
By default, bit7z uses the latest 7-Zip implementation of the Windows COM interfaces, which is incompatible with p7zip's (since 7-Zip v23.01).
This leads to problems like yours, where the 7z.so uses one implementation, and bit7z another, resulting in a crash.
You can build bit7z to be compatible with the p7zip's 7z.so by enabling the CMake option BIT7Z_USE_LEGACY_IUNKNOWN; this should fix your problem.

@gbook
Copy link
Author

gbook commented May 3, 2024 via email

@rikyoz
Copy link
Owner

rikyoz commented May 3, 2024

I see.
I'll try to replicate the issue

@gbook
Copy link
Author

gbook commented May 3, 2024 via email

@rikyoz
Copy link
Owner

rikyoz commented May 4, 2024

Unfortunately, I wasn't able to replicate the issue.

Specifically:

  • As I don't have access to RHEL 8, I've set up a VM running Fedora 28 (which is the base for RHEL 8).

  • For the tests, I've used the default GCC version (8.3.1), the default p7zip's 7z.so (package p7zip-plugins), and the default Qt 5 development packages provided on Fedora 28.

  • Inside the VM, I've built bit7z as follows:

    git clone https://github.com/rikyoz/bit7z && cd bit7z
    mkdir build && cd build
    cmake .. -DBIT7Z_AUTO_FORMAT=ON -DBIT7Z_USE_LEGACY_IUNKNOWN=ON
    cmake --build . --config Release
    
  • Always inside the VM, I created a barebone Qt 5 Widgets application project in Qt Creator that uses the bit7z library built as in the previous step.

    • I've done this to try replicate your issue, as it seems that your code is part of a Qt application.
  • My app GUI looks like this:
    image

    • The first QLineEdit and QPushButton couple allows to select the directory to be compressed.
    • The second one allows to select the destination archive.
    • The last QPushButton executes your code, which I wrapped inside a method of a dummy Compressor class:
    // compressor.h
    class Compressor {
        QString m;
      public:
        const QString& resultMessage() {
            return m;
        }
    
        bool compressDirectory(const QString& dir, const QString& archivePath) {
            try {
                using namespace bit7z;
        #ifdef Q_OS_WINDOWS
                Bit7zLibrary lib("C:/Program Files/7-Zip/7z.dll");
        #else
                Bit7zLibrary lib("/usr/libexec/p7zip/7z.so");
        #endif
                if (archivePath.endsWith(".zip", Qt::CaseInsensitive)) {
                    BitArchiveWriter archive(lib, BitFormat::Zip);
                    archive.setUpdateMode(UpdateMode::Update);
                    archive.addDirectory(dir.toStdString());
                    archive.compressTo(archivePath.toStdString());
                }
                else {
                    BitArchiveWriter archive(lib, BitFormat::SevenZip);
                    archive.setUpdateMode(UpdateMode::Update);
                    archive.addDirectory(dir.toStdString());
                    archive.compressTo(archivePath.toStdString());
                }
                m = "Successfully compressed directory [" + dir + "] to archive [" + archivePath + "]";
                return true;
            }
            catch ( const bit7z::BitException& ex ) {
                /* Do something with ex.what()...*/
                m = "Unable to compress directory into archive using bit7z library [" + QString(ex.what()) + "]";
                return false;
            }
        }
    };
    
    // mainwindow.cpp
    void MainWindow::on_pushButton_clicked() {
        Compressor compressor;
        bool result = compressor.compressDirectory(ui->directoryLineEdit->text(), ui->archiveLineEdit->text());
        if (result) {
            QMessageBox::information(this, tr("Compression successful"), compressor.resultMessage(), QMessageBox::Ok);
        } else {
            QMessageBox::critical(this, tr("Compression error"), compressor.resultMessage(), QMessageBox::Ok);
        }
    }
  • I've tested the code both by creating a Zip and a 7z archive, and it worked in both cases, without any crash:
    image
    image

@gbook
Copy link
Author

gbook commented May 4, 2024 via email

@gbook
Copy link
Author

gbook commented May 6, 2024

It worked! (once) I was using the 4.0.4 code and I updated to the 4.0.6, rebuilt it, and it worked. My program built, it ran, and created a .7z file successfully.

However, after that one time working, now my program doesn't build correctly :-( I don't know what changed, but now every time I build my program against the bit7z library I get this error

linking nidb
../../bin/squirrel//libsquirrel.so: undefined reference to `bit7z::BitInputArchive::ConstIterator::operator*()'
collect2: error: ld returned 1 exit status
make: *** [Makefile:353: nidb] Error 1

In my case nidb depends on libsquirrel which depends on libbit7z64. I'm able to build the libsquirrel library, which depends on bit7z. But when trying to build any executable that depends on bit7z, I get link errors like these:

linking squirrel
squirrel.o: In function `squirrel::RemoveDirectoryFromArchive(QString, QString, QString&)':
squirrel.cpp:(.text+0x18171): undefined reference to `bit7z::BitInputArchive::ConstIterator::operator*()'
squirrel.cpp:(.text+0x18399): undefined reference to `bit7z::BitInputArchive::ConstIterator::operator*()'
squirrel.o: In function `bit7z::BitExtractor<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::extractMatching(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<unsigned char, std::allocator<unsigned char> >&, bit7z::FilterPolicy) const':
squirrel.cpp:(.text._ZNK5bit7z12BitExtractorIRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15extractMatchingES8_S8_RSt6vectorIhSaIhEENS_12FilterPolicyE[_ZNK5bit7z12BitExtractorIRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15extractMatchingES8_S8_RSt6vectorIhSaIhEENS_12FilterPolicyE]+0xaf): undefined reference to `bit7z::BitInputArchive::ConstIterator::operator*()'
collect2: error: ld returned 1 exit status
make: *** [Makefile:313: squirrel] Error 1

@gbook
Copy link
Author

gbook commented May 6, 2024

Now it works, consistently. Building bit7z from scratch solved my problem. Thank you!

@gbook gbook closed this as completed May 6, 2024
@rikyoz
Copy link
Owner

rikyoz commented May 6, 2024

Building bit7z from scratch solved my problem.

The recent v4.0.6 fixed the operator* of the BitInputArchive's iterator, which couldn't be called on const iterator objects.

image

There was probably a mismatch between your bit7z's headers and binary, which was fixed by rebuilding it.

Thank you!

You're welcome!
Thank you for using bit7z! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants