[bugfix] wallet: Fix duplicate fileid detection #14320

pull ken2812221 wants to merge 2 commits into bitcoin:master from ken2812221:2018-09-25-wallet-duplicate-fileid-fix changing 3 files +30 −12
  1. ken2812221 commented at 2:42 pm on September 25, 2018: contributor

    The implementation in current master can not detect if the file ID is duplicate with flushed BerkeleyEnvironment. This PR would store the file ID in a global variable g_fileids and release it when the BerkeleyDatabase close. So it won’t have to rely on a Db*.

    Fix #14304

  2. ken2812221 force-pushed on Sep 25, 2018
  3. in src/wallet/db.cpp:28 in 4d5a58b1d2 outdated
    20@@ -20,6 +21,12 @@
    21 #include <boost/thread.hpp>
    22 
    23 namespace {
    24+
    25+struct BerkeleyFileid {
    26+    u_int8_t value[DB_FILE_ID_LEN];
    27+};
    28+std::unordered_map<std::string, BerkeleyFileid> g_fileids;
    


    ryanofsky commented at 3:32 pm on September 25, 2018:

    I think it’d be more correct to add a std::unordered_map<std::string, BerkeleyFileid> m_fileids member in BerkeleyEnvironment member instead of a g_fileids global because there can be duplicate filenames if the files are in different directories.

    Also, making this a member would be consistent with existing mapFileUseCount mapDb members there which are also maps indexed by filename. In the future it could be nice to consolidate the 3 maps.


    ken2812221 commented at 4:38 pm on September 25, 2018:
    Updated
  4. ryanofsky commented at 3:36 pm on September 25, 2018: member

    Great catch, I was surprised to see this bug. It seems like the problem here is that BerkeleyEnvironment::Flush actually fully unloads databases, so the check for duplicate fileids when opening a new database doesn’t work at all after flushing.

    I wonder if you could make a python test case out of the steps in #14304.

  5. ken2812221 force-pushed on Sep 25, 2018
  6. DrahtBot commented at 5:01 pm on September 25, 2018: member
    • #14531 (Replace fs::relative call with custom GetRelativePath by promag)
    • #11911 (Free BerkeleyEnvironment instances when not in use by ryanofsky)

    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.

  7. in src/wallet/db.cpp:43 in 839142c826 outdated
    48-        if (item.second && item.second->get_mpf()->get_fileid(item_fileid) == 0 &&
    49-            memcmp(fileid, item_fileid, sizeof(fileid)) == 0) {
    50-            const char* item_filename = nullptr;
    51-            item.second->get_dbname(&item_filename, nullptr);
    52+    for (const auto& item : env.m_fileids) {
    53+        if (item.first != filename && memcmp(fileid.value, item.second.value, sizeof(fileid)) == 0) {
    


    promag commented at 5:10 pm on September 25, 2018:
    move memcmp to BerkeleyFileid::operator==?

    ken2812221 commented at 8:31 pm on September 25, 2018:
    done
  8. in src/wallet/db.cpp:50 in 0ce468502b outdated
    56-                item_filename ? item_filename : "(unknown database)"));
    57+                HexStr(std::begin(item.second.value), std::end(item.second.value)), item.first));
    58         }
    59     }
    60+
    61+    env.m_fileids.emplace(filename, fileid);
    


    ryanofsky commented at 5:45 pm on September 25, 2018:
    Since CheckUniqueFileid is called on all BerkeleyEnvironment instances, this will incorrectly add the filename to unrelated BerkeleyEnvironment instances that don’t actually contain filename. I’d suggest dropping this line, adding a BerkeleyFileid& fileid output parameter to CheckUniqueFileid, and passing in this->env->m_fileids[strFilename] where CheckUniqueFileid is called in BerkeleyBatch::BerkeleyBatch.

    ken2812221 commented at 8:32 pm on September 25, 2018:
    done
  9. in src/fs.cpp:92 in 87a39fcdd6 outdated
    88@@ -89,7 +89,7 @@ bool FileLock::TryLock()
    89         return false;
    90     }
    91     _OVERLAPPED overlapped = {0};
    92-    if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 0, 0, &overlapped)) {
    93+    if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, -1, -1, &overlapped)) {
    


    ryanofsky commented at 5:53 pm on September 25, 2018:

    In commit “util: Fix broken Windows file lock”

    Can you describe how the lock is broken in the commit message?


    ken2812221 commented at 7:42 pm on September 25, 2018:

    That was introduced by #13862. I assume that it could work with length 0 if it is a exclusive lock, but it doesn’t. I would have to specify -1, -1 to make it work.

    The boost implementation:

    https://github.com/boostorg/interprocess/blob/8b3621353017aa527a22124655c9458d0b64b358/include/boost/interprocess/detail/os_file_functions.hpp#L230-L243

  10. ken2812221 force-pushed on Sep 25, 2018
  11. ken2812221 force-pushed on Sep 25, 2018
  12. ken2812221 force-pushed on Sep 25, 2018
  13. in src/wallet/db.cpp:826 in f31c3fcc88 outdated
    825@@ -826,6 +826,8 @@ void BerkeleyDatabase::Flush(bool shutdown)
    826             LOCK(cs_db);
    


    ken2812221 commented at 7:52 pm on September 25, 2018:
    Note that if two or more BerkeleyDatabase share the same BerkeleyEnvironment, the env would be a wild pointer after the first call.

    ryanofsky commented at 8:25 pm on September 25, 2018:
    Good catch. This appears to be a bug introduced in 0b82bac76d0f842bd2294a290388536951fbc576 from #13111 and then tweaked in a769461d5e37ddcb771ae836254fdc69177a28c4 in #12493. It seems not directly related to this issue, so probably best addressed separately.

    promag commented at 10:40 am on October 24, 2018:
    Good catch indeed. The bug was not introduced in 0b82bac but in a769461d?

    ryanofsky commented at 3:30 pm on October 24, 2018:

    Thread #14320 (review)

    Good catch indeed. The bug was not introduced in 0b82bac but in a769461?

    0b82bac76d0f842bd2294a290388536951fbc576 added the call to erase the environment too early and a769461d5e37ddcb771ae836254fdc69177a28c4 just moved the call, IIUC.

  14. in src/wallet/db.cpp:506 in f31c3fcc88 outdated
    502@@ -503,8 +503,8 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
    503             // be implemented, so no equality checks are needed at all. (Newer
    504             // versions of BDB have an set_lk_exclusive method for this
    505             // purpose, but the older version we use does not.)
    506-            for (const auto& env : g_dbenvs) {
    507-                CheckUniqueFileid(env.second, strFilename, *pdb_temp);
    508+            for (auto& env : g_dbenvs) {
    


    ryanofsky commented at 8:10 pm on September 25, 2018:
    I think you could restore auto& env to const auto& env here.
  15. ken2812221 force-pushed on Sep 25, 2018
  16. in src/wallet/db.cpp:43 in 8389ce8fb0 outdated
    47-        if (item.second && item.second->get_mpf()->get_fileid(item_fileid) == 0 &&
    48-            memcmp(fileid, item_fileid, sizeof(fileid)) == 0) {
    49-            const char* item_filename = nullptr;
    50-            item.second->get_dbname(&item_filename, nullptr);
    51+    for (const auto& item : env.m_fileids) {
    52+        if (item.first != filename && fileid == item.second) {
    


    ryanofsky commented at 8:19 pm on September 25, 2018:

    I think item.first != filename condition makes the check too loose again because the same filename can exist in different directories (and we’d expect pretty much all wallet directories to have a wallet.dat file).

    Perhaps change condition to: if (item.second == fileid && !(&item.second == &fileid))

  17. in src/wallet/db.cpp:56 in 8389ce8fb0 outdated
    50@@ -56,6 +51,11 @@ CCriticalSection cs_db;
    51 std::map<std::string, BerkeleyEnvironment> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to open db environment.
    52 } // namespace
    53 
    54+bool BerkeleyFileid::operator==(const BerkeleyFileid& b) const
    55+{
    56+    return memcmp(this, &b, sizeof(BerkeleyFileid)) == 0;
    


    ryanofsky commented at 8:20 pm on September 25, 2018:

    It might be safer if memcmp compared just the value field rather than the whole object, since it seems possible the compiler could pad the objects. Maybe:

    0return memcmp(this->field, b.field, sizeof(this->field)) == 0;
    
  18. fanquake added the label Wallet on Sep 25, 2018
  19. ken2812221 force-pushed on Sep 26, 2018
  20. in src/wallet/db.cpp:829 in cb4af1969c outdated
    825@@ -826,6 +826,8 @@ void BerkeleyDatabase::Flush(bool shutdown)
    826             LOCK(cs_db);
    827             g_dbenvs.erase(env->Directory().string());
    828             env = nullptr;
    829+        } else {
    


    ryanofsky commented at 6:22 am on September 26, 2018:
    Why not call m_fileds.erase if shutdown is true? It seems ok to only erase if shutdown is false, but if there is a specific reason for not erasing when shutting down, it would be useful to note in a code comment.

    ken2812221 commented at 6:32 am on September 26, 2018:
    That would cause an access violation on Windows since it’s a wild pointer in the second call. Also, since the env is deleted when g_dbenvs.erase called, the map doesn’t exist anymore.
  21. ryanofsky commented at 6:26 am on September 26, 2018: member
    utACK cb4af1969c03b56bc18b63286627922db86743d2. Thanks for the fix and all the followup!
  22. ken2812221 force-pushed on Sep 26, 2018
  23. ken2812221 renamed this:
    wallet: Fix duplicate fileid detection
    [bugfix] wallet: Fix duplicate fileid detection
    on Sep 27, 2018
  24. MarcoFalke commented at 4:20 pm on September 27, 2018: member
    Is this for backport?
  25. ken2812221 force-pushed on Sep 27, 2018
  26. ryanofsky commented at 4:35 pm on September 27, 2018: member

    Is this for backport?

    Could be backported, but I think the benefit would be very minimal. I think you have to literally copy a wallet database file and use the loadwallet RPC in order to trigger the missing error check that this PR restores.

  27. ryanofsky commented at 8:49 pm on September 27, 2018: member
    utACK f936b8d14bfa8c758984430181db20514d34accd. Only change since previous review is adding code comment.
  28. DrahtBot commented at 3:33 am on September 28, 2018: member
    Coverage Change (pull 14320) Reference (master)
    Lines +0.0019 % 87.0361 %
    Functions -0.0049 % 84.1130 %
    Branches -0.0008 % 51.5451 %
  29. DrahtBot added the label Needs rebase on Oct 20, 2018
  30. ken2812221 force-pushed on Oct 21, 2018
  31. ken2812221 commented at 7:47 am on October 21, 2018: contributor
    Rebased
  32. DrahtBot removed the label Needs rebase on Oct 21, 2018
  33. ken2812221 force-pushed on Oct 21, 2018
  34. ken2812221 force-pushed on Oct 21, 2018
  35. ken2812221 force-pushed on Oct 21, 2018
  36. ken2812221 force-pushed on Oct 21, 2018
  37. ken2812221 force-pushed on Oct 21, 2018
  38. ken2812221 force-pushed on Oct 21, 2018
  39. ken2812221 force-pushed on Oct 21, 2018
  40. in test/functional/wallet_multiwallet.py:78 in 02b6bd343d outdated
    74             wallet_names.remove('w7_symlink')
    75+            wallet_exclude = {'w7'}
    76         extra_args = ['-wallet={}'.format(n) for n in wallet_names]
    77         self.start_node(0, extra_args)
    78-        assert_equal(set(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), set(['', 'w3', 'w2', 'sub/w5', 'w7', 'w7', 'w1', 'w8', 'w']))
    79+        assert_equal(set(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), set(['', 'w3', 'w2', os.path.join('sub', 'w5'), 'w7', 'w7', 'w1', 'w8', 'w']) - wallet_exclude)
    


    ryanofsky commented at 9:11 pm on October 22, 2018:
    Note: It looks os.path.join change is not directly related to this PR, but is just a fix for listwalletdir (added in #14291) on windows.

    ryanofsky commented at 9:12 pm on October 22, 2018:

    ‘w7’, ‘w7’

    Code precedes this PR, but I think listing w7 twice has no effect.


    promag commented at 10:14 pm on October 22, 2018:
    This is changed in #14531.
  41. ryanofsky approved
  42. ryanofsky commented at 9:15 pm on October 22, 2018: member
    utACK 02b6bd343da296dc29ea017447b18c9afa13b5e3. Only changes since last review are rebase and listwalletdir fixes.
  43. ken2812221 force-pushed on Oct 24, 2018
  44. ken2812221 commented at 7:13 am on October 24, 2018: contributor
    Just split appveyor part to #14559 to make this PR easier to review.
  45. in src/wallet/db.cpp:835 in ef16fc5da6 outdated
    825@@ -826,6 +826,10 @@ void BerkeleyDatabase::Flush(bool shutdown)
    826             LOCK(cs_db);
    827             g_dbenvs.erase(env->Directory().string());
    828             env = nullptr;
    829+        } else {
    830+            // To avoid accessing a map that has already deconstructed, do not call this when shutdown is true. g_dbenvs.erase would also erase this value.
    831+            // TODO: get rid of wild pointers
    832+            env->m_fileids.erase(strFile);
    


    ryanofsky commented at 2:23 pm on October 24, 2018:

    It might not be clear what “wild pointers” refers to in this todo (laanwj asked about it here: #14531 (review)). Wild pointers could mean either dead pointers or raw pointers, but I think the TODO is referring to the bug described here: #14320 (review). Maybe could be expanded as:

    0// TODO: To avoid g_dbenvs.erase erasing the environment prematurely after the
    1// first database shutdown when multiple databases are open in the same
    2// environment, should replace raw database `env` pointers with shared or weak
    3// pointers, or else separate the database and environment shutdowns so
    4// environments can be shut down after databases.
    
  46. ryanofsky commented at 2:34 pm on October 24, 2018: member
    utACK ef16fc5da6ca6b33d4a92e509d627d908f8ed995. Only change since last review is dropping appveyor commit and related wallet_multiwallet.py test fixes.
  47. in src/wallet/db.h:29 in ef16fc5da6 outdated
    24 #include <db_cxx.h>
    25 
    26 static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
    27 static const bool DEFAULT_WALLET_PRIVDB = true;
    28 
    29+struct BerkeleyFileid {
    


    promag commented at 2:35 pm on October 24, 2018:
    @laanwj suggested BerkeleyFileId. I also suggest WalletDatabaseFileId or DBFileId.
  48. ken2812221 force-pushed on Oct 24, 2018
  49. wallet: Fix duplicate fileid 2d796faf62
  50. tests: add test case for loading copied wallet twice 4ea77320c5
  51. ken2812221 force-pushed on Oct 24, 2018
  52. ken2812221 commented at 3:13 pm on October 24, 2018: contributor

    ef16fc5 -> 4ea7732

    1. Rename BerkeleyFileid -> WalletDatabaseFileId (@promag)
    2. Added @ryanofsky’s comments
  53. ryanofsky approved
  54. ryanofsky commented at 3:18 pm on October 24, 2018: member
    utACK 4ea77320c5f0b275876be41ff530bb328ba0cb87. Only changes are fileid class rename and todo comment.
  55. promag commented at 3:32 pm on October 24, 2018: member
    Tested ACK 4ea7732, new test fails without this fix.
  56. laanwj commented at 3:37 pm on October 24, 2018: member
    utACK 6241eb3224d95ea04c04dcab2dac88687f49440e
  57. laanwj merged this on Oct 24, 2018
  58. laanwj closed this on Oct 24, 2018

  59. laanwj referenced this in commit 2b88f67e0b on Oct 24, 2018
  60. ken2812221 deleted the branch on Oct 24, 2018
  61. MarcoFalke referenced this in commit 613fc95ee4 on Oct 24, 2018
  62. promag referenced this in commit 0e2d070905 on Mar 11, 2019
  63. promag referenced this in commit 03a9a82240 on Mar 11, 2019
  64. promag referenced this in commit 8965b6ab47 on Mar 11, 2019
  65. promag referenced this in commit 34da2b7c76 on Mar 11, 2019
  66. laanwj referenced this in commit 6cf81b01b4 on Mar 20, 2019
  67. sidhujag referenced this in commit f77f29313e on Mar 28, 2019
  68. sidhujag referenced this in commit dfdc72e534 on Mar 28, 2019
  69. sidhujag referenced this in commit 3ee64a0aa7 on Mar 28, 2019
  70. uhliksk referenced this in commit f3b3b2bbd0 on Apr 21, 2019
  71. uhliksk referenced this in commit 92b54286b0 on Apr 21, 2019
  72. Rishabh42 referenced this in commit ce3547fae6 on Apr 22, 2019
  73. uhliksk referenced this in commit cd29398e08 on May 1, 2019
  74. uhliksk referenced this in commit 6396a64765 on May 1, 2019
  75. jasonbcox referenced this in commit 8915b2f748 on Oct 25, 2019
  76. xdustinface referenced this in commit 3738170471 on Apr 4, 2021
  77. xdustinface referenced this in commit dc09345e28 on Apr 4, 2021
  78. xdustinface referenced this in commit 85349ca1f7 on Apr 4, 2021
  79. xdustinface referenced this in commit 86357cc55f on Apr 5, 2021
  80. xdustinface referenced this in commit 3bee6d011c on Apr 13, 2021
  81. 5tefan referenced this in commit 12d24c70f4 on Aug 14, 2021
  82. MarcoFalke locked this on Sep 8, 2021

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: 2024-12-18 15:12 UTC

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