util: Check write failures before renaming settings.json #35384

pull sh011 wants to merge 1 commits into bitcoin:master from sh011:sh011-35373-improve-error-msg changing 3 files +11 −3
  1. sh011 commented at 2:57 PM on May 26, 2026: contributor

    This PR Fixes #35373. The error message was updated from: "This is probably caused by disk corruption or a crash" to: "This is probably caused by a full disk, disk corruption or a crash"

    The following files were updated:

    1. src/common/settings.cpp -- Updated the main string formatting for the parse failure.
    2. src/test/settings_tests.cpp -- Updated the exact string expectation in the C++ unit test.
    3. test/functional/feature_settings.py -- Updated the expected error message in the Python test suite.

    Configured the Bitcoin Core project natively on Windows using Visual Studio (cmake --preset vs2026-static -DBUILD_GUI=OFF) and it compiled with 100% of the C++ tests passed successfully (347 out of 347).

  2. DrahtBot commented at 2:57 PM on May 26, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35384.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK winterrdog, sedited, maflcko, ryanofsky

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35527 (Treat empty settings file as missing by benthecarman)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  3. sh011 renamed this:
    Fix for #35373. Updated Error Message
    log: Fix for #35373 -- Updated Error Message
    on May 26, 2026
  4. DrahtBot added the label Utils/log/libs on May 26, 2026
  5. pinheadmz commented at 3:02 PM on May 26, 2026: member

    We have checks in other parts of the code for disk space. Why isn't that being used here to provide specific correct feedback?

  6. sh011 commented at 3:44 PM on May 26, 2026: contributor

    Hi @pinheadmz , the original change was done as part of the recommendation by the bot for the fix. But based on your comments, I believe it's a better approach so I have updated the PR with new commit to use CheckDiskSpace utility and adjust errors accordingly. Please have a look and let me know if that fixes the issue. Thanks!

  7. pinheadmz commented at 4:21 PM on May 26, 2026: member

    is @sys-dev a bot ?

  8. sh011 commented at 4:36 PM on May 26, 2026: contributor

    @pinheadmz I wouldn't know but looks like it.

  9. in src/common/settings.cpp:90 in af44551cf0
      86 | @@ -86,9 +87,15 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
      87 |  
      88 |      SettingsValue in;
      89 |      if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) {
      90 | -        errors.emplace_back(strprintf("Settings file %s does not contain valid JSON. This is probably caused by disk corruption or a crash, "
      91 | -                                      "and can be fixed by removing the file, which will reset settings to default values.",
      92 | -                                      fs::PathToString(path)));
      93 | +        if (!CheckDiskSpace(path.parent_path())) {
    


    maflcko commented at 7:12 PM on May 26, 2026:

    I don't think this is correct. The corruption will happen when writing the file, not when reading it, which may happen a long time after the out-of-space caused the corruption and the out-of-space may no longer be visible, assuming the init can even get here when the out-of-space is still present?


    sh011 commented at 2:45 AM on May 27, 2026:

    Based on your comments, the right place to add CheckDiskSpace() is in the WriteSettings function that will check disk space before writing and if space is low, it will add an error and refuse to write preventing the corruption from happening in the first place. Also, I feel the the read-time error message update (adding "a full disk" to possible causes) should be a fallback for cases where the corruption already happened.

    I have updated the PR with these changes, request you to please have a look.


    sys-dev commented at 3:46 AM on May 27, 2026:

    to be clear, here are the full log entries that occurred:

    bitcoind | Error: Settings file could not be read: bitcoind | - Settings file /home/bitcoin/.bitcoin/settings.json does not contain valid JSON. This is probably caused by disk corruption or a crash, and can be fixed by removing the file, which will reset settings to default values.

    When I inspected the file /home/bitcoin/.bitcoin/settings.json it was there, but was empty (zero length).

    HTH

  10. sys-dev commented at 3:26 AM on May 27, 2026: none

    hello all,

    actually I'm not a bot. lol. just used LLM to generate the issue blurbs.

    the message surfaced during IBD log messages and fooled me into a long troubleshoot of a new hardware build. lots of variables.

    I posted this issue to hopefully result in a simple improvement to the error message to hint that it could be a full disk.

    The real-world failure mode that motivated this issue:

    • Ubuntu Server fresh install with default LVM (allocates only 100G of available space)
    • Bitcoin IBD fills the 100G LV
    • settings.json zero-written, node reports "disk corruption"
    • Actual cause was full disk, not corruption

    thanks so much @sh011 for taking this improvement on, and others here reviewing. If it lands, I think it can save others some time and confusion if disk is full.

  11. maflcko commented at 7:17 AM on May 28, 2026: member
  12. sh011 force-pushed on May 28, 2026
  13. sh011 commented at 3:37 PM on May 28, 2026: contributor

    Hi @maflcko have squashed my commits into one. Please let me know if anything else is required.

  14. fanquake renamed this:
    log: Fix for #35373 -- Updated Error Message
    util: improve settings.json error message to mention full disk
    on May 28, 2026
  15. sh011 renamed this:
    util: improve settings.json error message to mention full disk
    log: Fix for #35373 -- Updated Error Message util: improve settings.json error message to mention full disk
    on May 28, 2026
  16. winterrdog commented at 9:46 PM on May 28, 2026: contributor

    Please let me know if anything else is required. @sh011 there's a pending review comment that you might wanna address. it poses an interesting case, check it out

  17. sh011 commented at 4:02 AM on May 29, 2026: contributor

    Hi @winterrdog I have already addressed the review comment with the fix where now CheckDiskSpace() is being used in the WriteSettings function that will check disk space before writing and throw an error if space is low. Hope that resolves the query.

  18. fanquake renamed this:
    log: Fix for #35373 -- Updated Error Message util: improve settings.json error message to mention full disk
    util: improve settings.json error message to mention full disk
    on May 29, 2026
  19. in src/common/settings.cpp:149 in 27d51d1bf3 outdated
     144 | +        errors.emplace_back(strprintf("Error: Unable to write settings file %s", fs::PathToString(path)));
     145 | +        if (!CheckDiskSpace(path.parent_path())) {
     146 | +            errors.emplace_back(strprintf("Error: Disk space is low for %s", fs::PathToString(path.parent_path())));
     147 | +        }
     148 | +        return false;
     149 | +    }
    


    winterrdog commented at 9:50 PM on May 29, 2026:

    i think the watchdog is probably the right place for disk space monitoring. it's proactive, runs continuously (every 5 mins), has a proper threshold, and shuts the node down cleanly before damage spreads. and when disk space gets critically low, the OS itself usually starts signaling that something is wrong too, other processes start failing, logs fill up, the system becomes obviously unhealthy and use-less. because of that, i'm not sure adding CheckDiskSpace inside WriteSettings meaningfully improves discoverability for the user

    from #35373:

    A full disk is a common real-world cause of this exact failure — the file exists but contains zero bytes, producing invalid JSON. The current message does not mention this possibility, leading users to investigate hardware corruption and crashes when the actual cause is simply insufficient disk space.

    it seems like the reporter's actual pain point was not "I didn't realise my disk was full," but rather "I got a confusing error message and started suspecting hardware corruption." the full disk became obvious later; the non-obvious part was the connection between a full disk and an empty settings.json

    so i wonder if the CheckDiskSpace addition may be addressing a problem that already has multiple layers of handling i.e. the watchdog from init.cpp, the OS, and other failing processes, while the real gap here is mostly a UX issue with the error wording itself

    IMO, the one-line message fix already addresses the reporter's actual confusion pretty directly, which makes me think keeping the scope narrow may be the cleaner approach


    sys-dev commented at 2:14 AM on May 30, 2026:

    hello @winterrdog,

    yes, the combo of "corruption" message with no mention of "disk full" and the empty file caused the confusion.

    If the disk is full, with the current WriteSettings logic...

    1. open succeeds and truncates the file
    2. doesn't check for errors on the write or the close
    3. returns true

    This explains the empty file and no record of any errors.

    It would seem good to at least add error checks for both write and close, log any errors, and return false.


    sys-dev commented at 7:09 PM on May 30, 2026:

    The current WriteSettings logic is the root cause. It "corrupts" the settings file by truncating it and silently ditching out when the disk is full.

    If WriteSettings gets fixed so it doesn't clobber the settings file, the other read error message won't appear and its message text could be left as-is.

    This could be done by adding logic to write to a tmp file something like this:

    bool WriteSettings(const fs::path& path,
        const std::map<std::string, SettingsValue>& values,
        std::vector<std::string>& errors)
    {
        SettingsValue out(SettingsValue::VOBJ);
        // Add auto-generated warning comment
        out.pushKV(SETTINGS_WARN_MSG_KEY, strprintf("This file is automatically generated and updated by %s. Please do not edit this file while the node "
                                                    "is running, as any changes might be ignored or overwritten.", CLIENT_NAME));
        // Push settings values
        for (const auto& value : values) {
            out.pushKVEnd(value.first, value.second);
        }
        // Create temporary file in case the settings file is not writable
        fs::path tmp = path;
        tmp += ".tmp";
    
        std::ofstream file;
        file.open(tmp.std_path());
        if (file.fail()) {
            errors.emplace_back(strprintf("Error: Unable to open tmp settings file %s for writing (disk full?)", fs::PathToString(path)));
            return false;
        }
        file << out.write(/* prettyIndent= */ 4, /* indentLevel= */ 1) << std::endl;
        file.close();
        if (file.fail()) {
            errors.emplace_back(strprintf("Error: Unable to write tmp settings file %s (disk full?)", fs::PathToString(path)));
            fs::remove(tmp);
            return false;   
        }                   
        // Rename tmp file to settings file
        std::error_code ec; 
        fs::rename(tmp, path, ec);
        if (ec) {           
            errors.emplace_back(strprintf("Error: Unable to save settings file %s (disk full?)", fs::PathToString(path)));
            fs::remove(tmp);
            return false;   
        }                   
        return true;
    }
    
  20. sh011 force-pushed on May 31, 2026
  21. sh011 commented at 5:43 PM on May 31, 2026: contributor

    Hi @winterrdog @sys-dev, thanks for the insights.

    I understood that watchdog already handles disk space monitoring proactively, so adding CheckDiskSpace() inside WriteSettings is redundant. Also, based on the root cause of the silent corruption, I've updated the PR with a single, squashed commit that takes a cleaner approach based on this feedback:

    1. Removed the redundant CheckDiskSpace() call.
    2. Added proper error checking for file.fail() after both writing to the stream and calling file.close() in WriteSettings. This prevents the silent truncation/corruption bug when the disk is full.
    3. Kept the read-time error message improvement ("This is probably caused by a full disk...") to help users who might still encounter this state from older versions.

    This catches write errors while keeping the scope narrow. Please let me know what you think..

  22. in src/common/settings.cpp:150 in 8219bf95dc outdated
     145 | +    }
     146 |      file.close();
     147 | +    if (file.fail()) {
     148 | +        errors.emplace_back(strprintf("Error: Unable to close settings file %s", fs::PathToString(path)));
     149 | +        return false;
     150 | +    }
    


    winterrdog commented at 6:19 PM on June 1, 2026:

    @sh011

    why is the file.fail() check after file.close() needed?

    at that point std::endl has already flushed the data to the settings file on disk. if the write succeeded, what failure can file.close() report that is not already captured by file.fail() after the write ?


    sh011 commented at 3:19 AM on June 2, 2026:

    I've noticed from my experience that checking for errors after close() is considered a C++ best practice for file writing.

    The reasoning is because on certain Network File Systems, OS might accept the flushed data into its own network buffers and return success during the flush. It's only when you call close() that the OS communicates with the remote server, realizes the disk is full and reports the error.

    Either way, if you feel this is unnecessary, I can go ahead and remove the check. Please do let me know what you think.


    sh011 commented at 3:10 PM on June 17, 2026:

    @winterrdog I am resolving this conversation as there is an active conversation below reviewing the changes, have also provided my explanation as to why I want to retain the check. Let me know if otherwise.

  23. DrahtBot added the label CI failed on Jun 5, 2026
  24. maflcko closed this on Jun 9, 2026

  25. maflcko reopened this on Jun 9, 2026

  26. sh011 commented at 4:11 AM on June 10, 2026: contributor

    @winterrdog @maflcko @sys-dev Is there a discussion happening on this? the PR is pending, if there's no issues, request you to please have a look on the same.

  27. DrahtBot removed the label CI failed on Jun 10, 2026
  28. fanquake commented at 9:55 AM on June 17, 2026: member

    cc @ryanofsky, given comments in #35527 (review)

  29. maflcko commented at 10:01 AM on June 17, 2026: member

    @winterrdog @maflcko @sys-dev Is there a discussion happening on this? the PR is pending, if there's no issues, request you to please have a look on the same.

    When I look at the review tab, there are outstanding review comments, which need to be replied to by the author.

  30. in src/common/settings.cpp:89 in 8219bf95dc
      85 | @@ -86,7 +86,7 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
      86 |  
      87 |      SettingsValue in;
      88 |      if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) {
      89 | -        errors.emplace_back(strprintf("Settings file %s does not contain valid JSON. This is probably caused by disk corruption or a crash, "
      90 | +        errors.emplace_back(strprintf("Settings file %s does not contain valid JSON. This is probably caused by a full disk, disk corruption or a crash, "
    


    maflcko commented at 10:12 AM on June 17, 2026:

    I don't think this full-disk failure can happen, now that you check for a read failure. (RenameOver is meant to be atomic, so if it happens, then that is a bug in RenameOver and not an issue with a full disk)


    ryanofsky commented at 1:10 PM on June 17, 2026:

    re: #35384 (review)

    In commit "util: improve settings.json error message to mention full disk" (8219bf95dcd0a24c555c95932dc5e5da2222d97e)

    Agree with Marco the WriteSettings changes below should make this much less likely to be triggered by a full disk so full disk should probably not be listed first. Chatgpt suggests "This may be caused by a crash, power loss, full disk, or storage error" which I think is more accurate and reads well.


    maflcko commented at 1:36 PM on June 17, 2026:

    The rename is atomic, so a crash shouldn't have caused this issue before or after this pull. Also a full disk should not cause this issue anymore after this pull. I think only a software bug, hardware corruption or maybe power loss can lead to this now.


    ryanofsky commented at 2:01 PM on June 17, 2026:

    re: #35384 (review)

    Agree a pure application crash should not cause this, but a system crash like a kernel panic could, and I think "crash" is the simplest way to describe for a user the type of event that could cause this, and is probably best to start with.

    Also agree a full disk should now be less likely to cause this error after the bugfix, but could still be a possible cause especially since this code is not calling fsync, so a logical write seem to succeed but physical write could fail, and it is good to mention as a possibility especially since we have a report about someone knowing about the disk space issue, but not connecting the disk space issue to this error.

    Anyway I think suggested phrasing is very good but would be ok with something else if you have a different suggestion.


    sys-dev commented at 1:34 AM on June 18, 2026:

    @maflcko @ryanofsky

    There's a subtler issue here that's worth calling out explicitly. Snippet from WriteSettings:

    std::ofstream file;
    file.open(path.std_path());
    if (file.fail()) {
        errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", fs::PathToString(path)));
        return false;
    }
    

    The real problem is that file.open() truncates the existing file (effectively O_TRUNC semantics) before any write happens, and this truncation succeeds even when the disk is full — truncating to zero length doesn't require free space, so the OS has no reason to error out at open() time. The subsequent write will fail as expected, but by then the previously-good settings file has already been clobbered.

    So returning false on write failure isn't enough on its own: it correctly reports the error, but the destructive truncation has already happened regardless.

    A more robust fix is to write to a temp file first, verify it opens and the write succeeds, and only then atomically rename it over the original. That way, a failed write never destroys the existing settings file — it just fails to update it.

    This is becoming more likely to bite people in practice: as chain state pushes toward 1TB, nodes running on 1TB drives will increasingly hit disk-full conditions. Fixing this means the existing error-handling path actually does its job, instead of being preempted by a silent truncation that masquerades as settings corruption.

    Suggested fix here

    Should a new issue be opened to address this?


    ryanofsky commented at 2:39 AM on June 18, 2026:

    re: #35384 (review)

    The real problem is that file.open() truncates the existing file (effectively O_TRUNC semantics) before any write happens, and this truncation succeeds even when the disk is full — truncating to zero length doesn't require free space, so the OS has no reason to error out at open() time. The subsequent write will fail as expected, but by then the previously-good settings file has already been clobbered.

    The previous settings file shouldn't be clobbered because WriteSettings is only being used to write to a temporary file:

    https://github.com/bitcoin/bitcoin/blob/1e169a8a6cb8ed0221042a9abbd121167ee02b29/src/common/args.cpp#L496

    If writing the temporary file fails, the previous file will not be overrwritten.


    sys-dev commented at 12:15 PM on June 18, 2026:

    common::WriteSettings is called from multiple places in the codebase.

    This call from CBanDB::Write is not protected:

    src/addrdb.cpp

    bool CBanDB::Write(const banmap_t& banSet)
    {
        std::vector<std::string> errors;
        if (common::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
            return true;
        }
    
        for (const auto& err : errors) {
            LogError("%s\n", err);
        }
        return false;
    }
    

    I can confirm that the node I experienced the issue on is using the setban cli command to periodically update the ban list.

    common::WriteSettings as it stands is an accident waiting to happen. every caller must protect. why not just fix it?


    winterrdog commented at 12:43 PM on June 18, 2026:

    I can confirm that the node I experienced the issue on is using the setban cli command to periodically update the ban list.

    care to say exactly what the issue was? (it will help with tracing what is broken)


    sys-dev commented at 1:54 PM on June 18, 2026:

    sure, here's the scenario

    • Ubuntu Server fresh install with default LVM (allocates only 100G of available space)
    • Bitcoin IBD fills the 100G LV
    • settings.json zero-written, node reports "disk corruption"
    • Actual cause was full disk, not corruption

    during IBD, the disk filled. bitcoind was running in a Docker container and I only captured 2 lines from the log from that incident:

    bitcoind  | Error: Settings file could not be read:
    bitcoind  | - Settings file /home/bitcoin/.bitcoin/settings.json does not contain valid JSON. This is probably caused by disk corruption or a crash, and can be fixed by removing the file, which will reset settings to default values.
    

    above those lines were UpdateTip messages, like this:

    bitcoind  | UpdateTip: new best=000000000000000002a2e1ddc345b9fe700aa572274cb42e2ebd0a47e7cab403 height=381767 version=0x00000003 log2_work=83.551296 tx=90610866 date='2015-11-02T22:18:41Z' progress=0.066692 cache=1169.5MiB(8771598txo)
    bitcoind  | UpdateTip: new best=00000000000000000ed211b270583c6235f0ecf14611c94a5719ca69dfa81065 height=381768 version=0x00000003 log2_work=83.551323 tx=90612084 date='2015-11-02T22:30:06Z' progress=0.066693 cache=1169.5MiB(8771797txo)
    bitcoind  | UpdateTip: new best=000000000000000005aa0211fe4903d88391654976ae66ff94994769eb739460 height=381769 version=0x00000003 log2_work=83.551350 tx=90614091 date='2015-11-02T22:47:19Z' progress=0.066694 cache=1169.5MiB(8772360txo)
    

    No other signs of trouble locally in the log, which led me to the false conclusion that the disk was corrupted. The node did not crash, I checked the file /home/bitcoin/.bitcoin/settings.json and it contained zero bytes, which is indicative of truncation.


    winterrdog commented at 7:42 PM on June 18, 2026:

    interesting. did you try this with the changes from this PR or master? if not, maybe let's wait for it to land first and then confirm whether the issue still persists

    if you would rather not wait for a merge, you can also pull the PR locally and test against the branch directly

  31. ryanofsky approved
  32. ryanofsky commented at 1:16 PM on June 17, 2026: contributor

    Code review ACK 8219bf95dcd0a24c555c95932dc5e5da2222d97e. Thanks for this fix! This is definitely an improvement but current PR title and PR description and commit message are misleading so those should be updated before this is merged. Would suggest something like "Bugfix: Check write failures before renaming settings.json" for the title. I also left another suggestion about error message wording below.

  33. maflcko commented at 2:34 PM on June 17, 2026: member

    lgtm ACK 8219bf95dcd0a24c555c95932dc5e5da2222d97e

    At this point the error message hopefully ~never happens, so rewording it is not too important. The important fix is fixing the return value from true to false when the write didn't work.

    I presume the wrong return value exists since this code was written, so maybe this can be backported?

  34. DrahtBot renamed this:
    util: improve settings.json error message to mention full disk
    util: Check write failures before renaming settings.json
    on Jun 17, 2026
  35. util: Check write failures before renaming settings.json
    In WriteSettings(), verify that writing to the stream and closing it
    succeeded before returning true. This prevents RenameOver() from replacing
    a valid settings.json with a corrupted or zero-byte file when write limits
    or a full disk are encountered.
    
    Additionally, update the ReadSettings() parse failure message to mention
    power loss, full disk, or storage error as possible causes.
    
    Fixes #35373
    0654511e1b
  36. sh011 force-pushed on Jun 17, 2026
  37. sh011 commented at 3:24 PM on June 17, 2026: contributor

    @maflcko @ryanofsky

    Thanks for the reviews! I've updated the error message wording to the suggested phrasing and modified the tests to match. I've also updated the description, and commit message to highlight the WriteSettings bugfix instead of just the error message update. The PR title has already been updated by @DrahtBot. Request the other reviewers to resolve the old pending conversations which do not have any update or please update the same as to what needs to be done here (cc @sys-dev)

  38. in src/common/settings.cpp:147 in 0654511e1b
     138 | @@ -139,7 +139,15 @@ bool WriteSettings(const fs::path& path,
     139 |          return false;
     140 |      }
     141 |      file << out.write(/* prettyIndent= */ 4, /* indentLevel= */ 1) << std::endl;
     142 | +    if (file.fail()) {
     143 | +        errors.emplace_back(strprintf("Error: Unable to write settings file %s", fs::PathToString(path)));
     144 | +        return false;
     145 | +    }
     146 |      file.close();
     147 | +    if (file.fail()) {
    


    winterrdog commented at 8:07 PM on June 17, 2026:

    thanks for the explanation. it's right.

    but i'm wondering whether there are existing places in bitcoin core where we check the stream state after std::ofstream::close(). if not, what makes settings.cpp more special than others (wallet.dat, blockchain/chainstate database etc..) ?

    more generally, if delayed write errors at close time are important enough to account for, shouldn't we be applying that pattern consistently and pairing it with stronger guarantees such as fsync(), rather than introducing an isolated close() check here ?


    sh011 commented at 4:42 AM on June 19, 2026:

    Thanks for the feedback. Checking close() on std::ofstream here is isolated/inconsistent but does the job as you mentioned below, wouldn't hurt to keep. Resolving this conversation as per the below comment.

  39. maflcko added this to the milestone 32.0 on Jun 18, 2026
  40. maflcko added the label Needs Backport (31.x) on Jun 18, 2026
  41. winterrdog commented at 7:04 PM on June 18, 2026: contributor

    ACK 0654511e1b935d22fe6c88e3f5d5c7b336516222

    I still think the check after close() is fairly niche, but it does not hurt much to have it. Looks alright to me

  42. DrahtBot requested review from maflcko on Jun 18, 2026
  43. DrahtBot requested review from ryanofsky on Jun 18, 2026
  44. sedited approved
  45. sedited commented at 7:12 PM on June 18, 2026: contributor

    ACK 0654511e1b935d22fe6c88e3f5d5c7b336516222

  46. maflcko commented at 8:44 AM on June 19, 2026: member

    review ACK 0654511e1b935d22fe6c88e3f5d5c7b336516222 💧

    <details><summary>Show signature</summary>

    Signature:

    untrusted comment: signature from minisign secret key on empty file; verify via: minisign -Vm "${path_to_any_empty_file}" -P RWTRmVTMeKV5noAMqVlsMugDDCyyTSbA3Re5AkUrhvLVln0tSaFWglOw -x "${path_to_this_whole_four_line_signature_blob}"
    RUTRmVTMeKV5npGrKx1nqXCw5zeVHdtdYURB/KlyA/LMFgpNCs+SkW9a8N95d+U4AP1RJMi+krxU1A3Yux4bpwZNLvVBKy0wLgM=
    trusted comment: review ACK 0654511e1b935d22fe6c88e3f5d5c7b336516222 💧
    j6GlwA0Leyu/7casqkqmjHUr9JWjXLfkkzRptEgORH6OYpdZVapB8aPP01BR+C8rbctjzRKvmOE+Vis5flR+Cg==
    

    </details>

  47. ryanofsky commented at 10:53 AM on June 19, 2026: contributor

    It sounds like good followups to this PR would:

    • Start using RenameOver in CBanDB::Write to prevent similar problems from happening with banlist.json
    • Rename WriteSettings to be clear it is a lower level function and is unsafe to use without RenameOver
    • Look for other places where close is called without being checked and turn these into errors.

    Agree with @sys-dev, #35384 (review):

    "common::WriteSettings as it stands is an accident waiting to happen. every caller must protect. why not just fix it?" ()

    I don't think WriteSettings should choose filenames because that would make it more complicated and limit where it can be used, but I do think it should be renamed to something like WriteJsonUnsafe and that CBanDB::Write should be changed to use the RenameOver pattern.


    Partially disagree with @winterrdog #35384#pullrequestreview-4527776994, #35384 (review):

    I still think the check after close() is fairly niche, but it does not hurt much to have it. Looks alright to me

    Because of how close is documented in the linux manpage

    Dealing with error returns from close() A careful programmer will check the return value of close(), since it is quite possible that errors on a previous write(2) operation are reported only on the final close() that releases the open file description. Failing to check the return value when closing a file may lead to silent loss of data. This can especially be observed with NFS and with disk quota.

    But would agree if code is not checking close calls consistently, this should be fixed. Also agree that calling fsync would provide a stronger guarantee than just checking close if there's power loss or device disconnection. But if you do check close you should be a lot more protected from OS level failures (processes being killed, disk space errors).

  48. ryanofsky approved
  49. ryanofsky commented at 11:02 AM on June 19, 2026: contributor

    Code review ACK 0654511e1b935d22fe6c88e3f5d5c7b336516222 with commit message and error message improved since last review

    Note: PR title is up to date but PR description #35384#issue-4525160281 is incomplete and is still not mentioning the change to WriteSettings, which I think is the main change here.

  50. ryanofsky assigned ryanofsky on Jun 19, 2026
  51. ryanofsky merged this on Jun 19, 2026
  52. ryanofsky closed this on Jun 19, 2026

  53. fanquake referenced this in commit a5bc51bcdd on Jun 19, 2026
  54. fanquake removed the label Needs Backport (31.x) on Jun 19, 2026
  55. fanquake commented at 12:19 PM on June 19, 2026: member

    Backported to 31.x in #35331.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-06-21 02:51 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me