`LockAnnotation lock(::cs_main)` is a guarantee to the compiler thread analysis that `::cs_main` is locked (when it couldn't be determined otherwise).

Despite being annotated with the locking guarantee ...

https://github.com/bitcoin/bitcoin/blob/65526fc8666fef35ef908dbc225f706bef642c7e/src/interfaces/chain.cpp#L134-L138

... `getTipLocator()` reads `chainActive` (via `::ChainActive()`) without holding `cs_main`.

This can be verified by adding the following `AssertLockHeld(cs_main)`:

```
$ git diff
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 59623284d..9fc693a0f 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -134,6 +134,7 @@ class LockImpl : public Chain::Lock
     CBlockLocator getTipLocator() override
     {
         LockAnnotation lock(::cs_main);
+        AssertLockHeld(::cs_main);
         return ::ChainActive().GetLocator();
     }
     Optional<int> findLocatorFork(const CBlockLocator& locator) override
$ make check
../build-aux/test-driver: line 107: 12881 Aborted                 "$@" > $log_file 2>&1
FAIL: qt/test/test_bitcoin-qt
```
if (!chain().findBlock(result.last_failed_block, nullptr , nullptr , &time_max)) {
                throw std::logic_error("ScanForWalletTransactions returned invalid block hash");
            }
            return time_max + TIMESTAMP_WINDOW + 1;
        }
    }
    return startTime;
}
/**
 * Scan the block chain (starting in start_block) for transactions
 * from or to us. If fUpdate is true, found transactions that already
 * exist in the wallet will be updated.
 *
 * @param[in] start_block Scan starting block. If block is not on the active
 *                        chain, the scan will return SUCCESS immediately.
 * @param[in] stop_block  Scan ending block. If block is not on the active
 *                        chain, the scan will continue until it reaches the
 *                        chain tip.
 *
 * @return ScanResult returning scan information and indicating success or
 *         failure. Return status will be set to SUCCESS if scan was
 *         successful. FAILURE if a complete rescan was not possible (due to
 *         pruning or corruption). USER_ABORT if the rescan was aborted before
 *         it could complete.
 *
 * @pre Caller needs to make sure start_block (and the optional stop_block) are on
 * the main chain after to the addition of any new keys you want to detect
 * transactions for.
 */
CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, const uint256& stop_block, const WalletRescanReserver& reserver, bool fUpdate)