bitcoin/bitcoin

ReadAnchor throws exception on second run

asctime opened this issue · 6 comments

Is there an existing issue for this?

  • I have searched the existing issues

Current behaviour

std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
{
    std::vector<CAddress> anchors;
    try {
        DeserializeFileDB(anchors_db_path, CAddress::V2_DISK(anchors));
        LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
    } catch (const std::exception&) {
        anchors.clear();
    }

    fs::remove(anchors_db_path);
    return anchors;
}

On second run I would get:
EXCEPTION: NSt10filesystem7__cxx1116filesystem_errorE
filesystem error: cannot remove: No such file or directory [... \AppData\Roaming\Bitcoin\anchors.dat]
..\bitcoin-qt.exe in Runaway exception

Attempting blind delete on already-deleted file..

Expected behaviour

No crash on second run, this works for me:

std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
{
    std::vector<CAddress> anchors;
    try {
        DeserializeFileDB(anchors_db_path, CAddress::V2_DISK(anchors));
        LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
    } catch (const std::exception&) {
        anchors.clear();
    }

    if (fs::exists(anchors_db_path)) {
        try {
            fs::remove(anchors_db_path);
        } catch (const std::filesystem::filesystem_error& e) {
            LogPrintf("Error. %s could not be deleted: %s\n", fs::quoted(fs::PathToString(anchors_db_path.filename())), e.what());
        }
    }
    return anchors;
}

I emphasize that I am not very familiar with the code base, and there could be reasons for the way this is done. Just trying to better understand it really..

Steps to reproduce

Compile from source MinGW64, run twice..

Relevant log output

No response

How did you obtain Bitcoin Core

Compiled from source

What version of Bitcoin Core are you using?

26.1

Operating system and version

Windows, MinGW64 (using portable_endian.h)

Machine specifications

No response

Compile from source MinGW64, run twice..

What are the exact steps to reproduce, including the exact operating system version?

Does it happen with the compiled release version as well?

Ref: https://en.cppreference.com/w/cpp/filesystem/remove

Windows 10. I run the official binary on Linux and that's fine. Different compilers seem to manage the exception slightly differently? Regardless I'm not sure that a blind delete is the right way to do this, is all. Fixed on my side, I just wanted to point it out.

Different compilers seem to manage the exception slightly differently?

That should not be the case. The point of standard C++ library std::filesystem::remove is to provide the same interface behavior, regardless of compiler or operating system.

The specification says that false should be returned when the file does not exist, not an exception be thrown.

However, without exact steps to reproduce, using your compiler version, there is little that can be done here.

Regardless I'm not sure that a blind delete is the right way to do this, is all.

Right, it could make sense to catch the exception for other reasons, or not allow it to be thrown, but that is a different question.

According to #29930 (comment) the reason could be that you are using an experimental C++17 standard library, which has bugs?

That should not be the case. The point of standard C++ library std::filesystem::remove is to provide the same interface behavior, regardless of compiler or operating system.

The specification says that false should be returned when the file does not exist, not an exception be thrown.

Ah good point ><. I'll try it once with my clang install, it's a fair bit newer than my gcc which is due to be updated anyway. Ok to close from my side. Thanks.

Closing for now, but please leave a comment if there are more details to debug this issue.