sync: Replace LockAssertion with AssertLockHeldUnverified #19918

pull ryanofsky wants to merge 1 commits into bitcoin:master from ryanofsky:pr/lockb changing 3 files +40 −24
  1. ryanofsky commented at 3:43 pm on September 8, 2020: member

    AssertLockHeldUnverified does the same thing LockAssertion except it:

    • Correctly reports file and line number where assertion fails instead of location in sync.h.

    • Has a simpler syntax that doesn’t require declaring an unused variable name.

    • Should be harder to confuse with AssertLockHeld. Name should indicate it’s an unverified assertion not to be preferred when the safer verified assert is available.

    This also adds doxygen comments describing AssertLockHeld, AssertLockHeldUnverified, and AssertLockNotHeld macros.

    PR is compared with alternatives in https://github.com/bitcoin-core/bitcoin-devwiki/wiki/AssertLockHeld-PRs

  2. sync: Replace LockAssertion with AssertLockHeldUnverified
    AssertLockHeldUnverified does the same thing LockAssertion except it:
    
    - Correctly reports file and line number where assertion fails instead of
      location in sync.h.
    
    - Has a simpler syntax that doesn't require declaring an unused variable name.
    
    - Should be harder to confuse with AssertLockHeld. Name should indicate it's a
      weaker assertion not to be preferred when stronger compile time checks are
      available.
    
    This also adds doxygen comments describing AssertLockHeld,
    AssertLockHeldUnverified, and AssertLockNotHeld macros.
    3f8f78f135
  3. ryanofsky commented at 4:22 pm on September 8, 2020: member
    This PR is an alternative to #19865. I still think #19865 is a better approach would prefer it. I think having two lock assertions is unnecessarily confusing and while AssertLockHeld was useful historically before we had compile-time checks, now it just adds noise and inconsistency. If we are going to have two assertions, though, at least this PR should make it easier to compare and choose between them.
  4. DrahtBot added the label Docs on Sep 8, 2020
  5. DrahtBot added the label P2P on Sep 8, 2020
  6. hebasto commented at 4:38 pm on September 8, 2020: member

    LockAssertion was used (in a controversial way) in #19668 as it resolved problem. The initial #19668 version (https://github.com/hebasto/bitcoin/commits/pr19668.01) also had a commit that removes LockAssertion.

    So, Concept ACK on better tooling and naming.

  7. in src/sync.h:89 in 070803dc7e outdated
    86+ * greator or equal to 0).
    87+ *
    88+ * Use of this macro is neither encouraged nor discouraged in new code. It was
    89+ * historically used before compile time checks were available, but it may
    90+ * still be be useful for virtual methods or std::function callbacks where
    91+ * EXCLUSIVE_LOCKS_REQUIRED annotations are not enforced.
    


    ajtowns commented at 4:58 pm on September 8, 2020:

    developer-notes currently recommends “Combine annotations in function declarations with run-time asserts in function definitions”, think these recommendations are better off there, and certainly having conflicting recommendations is worse.

    I think the only case where it’s useful for virtual methods is if the parent class doesn’t need the lock, but the child class does – in that case invoking Parent* p = new Child(); p->func(); won’t trigger compile-time warnings but you could at least catch it with a runtime check. But I think that pattern probably should be considered a mistake anyway.

    As far as I know callbacks will need the WeaklyAssertLockHeld variant?


    vasild commented at 7:54 am on September 14, 2020:
    Maybe just drop the above paragraph as it contradicts with the developer nodes? IMO the latter is correct.

    ryanofsky commented at 8:23 pm on September 14, 2020:

    re: #19918 (review)

    developer-notes currently recommends “Combine annotations in function declarations with run-time asserts in function definitions”, think these recommendations are better off there, and certainly having conflicting recommendations is worse.

    I don’t love that recommendation, and the text doesn’t give a rationale for following it, but I dropped this paragraph. I wasn’t aware of other guidance and didn’t mean to conflict.

    I think the only case where it’s useful for virtual methods is if the parent class doesn’t need the lock, but the child class does – in that case invoking Parent* p = new Child(); p->func(); won’t trigger compile-time warnings but you could at least catch it with a runtime check. But I think that pattern probably should be considered a mistake anyway.

    As far as I know callbacks will need the WeaklyAssertLockHeld variant?

    re: “pattern probably should be considered a mistake.” IMO, the idea of having a compile time annotation whose only purpose at compile time is checking for the presence of a different compile-time annotation is a mistake. But given that, it makes sense to use AssertLockHeld instead of WeaklyAssertLockHeld to provide runtime checking inside a lambda annotated with EXCLUSIVE_LOCKS_REQUIRED called through a std::function, or inside an overridden virtual method annotated EXCLUSIVE_LOCKS_REQUIRED called through a base method which is not annotated.

    Deleted the comment, though, because I’m becoming convinced these asserts are hopeless to explain in detail. As long we’re are going to reject #19865 and have these ubiquitous asserts, the most useful practical advice will probably be to prefer using AssertLockHeld wherever possible and just fall back to WeaklyAssertLockHeld when the compiler gives an error you don’t understand.

    re: #19918 (review)

    Maybe just drop the above paragraph as it contradicts with the developer nodes? IMO the latter is correct.

    Thanks, dropped.


    ajtowns commented at 10:45 pm on September 14, 2020:

    But given that, it makes sense to use AssertLockHeld instead of WeaklyAssertLockHeld to provide runtime checking inside a lambda annotated with EXCLUSIVE_LOCKS_REQUIRED called through a std::function

    Both the current LockAssertion and your proposed WeaklyAssertLockHeld do runtime checking, so there’s no advantage there.

    I don’t think AssertLockHeld in lambdas ever makes much sense: there are two ways to use lambdas – one where thread safety annotations work as expected, and one where they’re broken because the lambda’s a callback passed to an unannotated function. In the former case you’re writing:

    0    LOCK(cs);
    1    [&]() EXCLUSIVE_LOCKS_REQUIRED(cs) { ++foo; }();
    

    where it’s already obvious that cs is held when the lambda is called, and you’re just adding the annotation to make the compiler happy.

    In the latter case, you’re writing:

    0    LOCK(cs_main);
    1    connman->ForEachNode([&](CNode* pnode) {
    2        WeaklyAssertLockHeld(cs_main);
    3        ...
    4    });
    

    because you can’t pass the fact that cs_main is still held through the un-annotated ForEachNode.

    inside an overridden virtual method annotated EXCLUSIVE_LOCKS_REQUIRED called through a base method which is not annotated.

    I think that is something we should go out of our way to avoid. Either the base method should be annotated as requiring the lock, or the overriding method should acquire the lock itself – with annotations, locking is part of the function signature, and you shouldn’t change the signature when overriding a method. We don’t have any code like this now, and I don’t think there’s any reason ever to, so I’m not sure it’s worth addressing it explicitly, but if we are, better to discourage it outright.


    aaronpuchert commented at 9:46 pm on September 16, 2020:
    Thread safety attributes sit on declarations and not on types, but we can check the virtual overriding case. I’ll have to look into that. (Theoretically it should be part of the type, but that would interact with other language features like overloading, so it was decided not to put it there.)

    ajtowns commented at 1:01 am on September 17, 2020:
    Looking through the “thread safety” issues on bugzilla, this seems similar to the idea “We could warn in -Wthread-safety-attributes if a declaration has attributes that weren’t visible on an earlier declaration.” from https://bugs.llvm.org/show_bug.cgi?id=42849
  8. in src/sync.h:101 in 070803dc7e outdated
     95+/**
     96+ * Assert at runtime that a mutex is locked. May be necessary to work around
     97+ * EXCLUSIVE_LOCKS_REQUIRED errors when the compiler can't determine that a
     98+ * mutex is locked.
     99+ */
    100+#define WeaklyAssertLockHeld(mutex) [&]() ASSERT_EXCLUSIVE_LOCK(mutex) { AssertLockHeldInternal(#mutex, __FILE__, __LINE__, &mutex); }()
    


    ajtowns commented at 6:04 pm on September 8, 2020:

    Maybe LOCK_ALREADY_HELD(mutex) would be better, comparable with LOCK(mutex)? This isn’t a particularly weak assertion in anyway I can see, it’s just one the compiler isn’t able to verify at compile time.

    “Assert that a mutex was already locked in any possible way this code could be reached. If DEBUG_LOCKORDER is defined, a runtime check that the mutex was actually locked by this thread will be made.” ? Without DEBUG_LOCKORDER this does nothing at runtime.

    Note that ASSERT_EXCLUSIVE_LOCK has slightly weird scoping behaviour; if x requires mutex m then:

    0    if (1) { WeaklyAssertLockHeld(m); }
    1    ++x;
    

    works fine, while

    0    extern int n;
    1    if (n > 1) { WeaklyAssertLockHeld(m); }
    2    ++x;
    

    tells you you need to hold the mutex to do ++x. I couldn’t come up with a case where this results in missing a warning though; but I’m not super-confident in it, as compared to being tightly bounded by scopes the way SCOPED_LOCKABLE is.


    vasild commented at 8:02 am on September 14, 2020:

    In non-debug build a code like:

    0WeaklyAssertLockHeld(mutex_required_for_x);
    1x = 1;
    

    where the mutex is not held will not produce a compilation warning and will not assert at runtime. So the unprotected access will actually happen. This is because ASSERT_EXCLUSIVE_LOCK tells the compiler we are going to check, but we actually don’t check (in non-debug build). Maybe remove ASSERT_EXCLUSIVE_LOCK in non-debug builds, or at least clearly explain in the comment the dangers of using this.


    ryanofsky commented at 8:24 pm on September 14, 2020:

    re: #19918 (review)

    Maybe LOCK_ALREADY_HELD(mutex) would be better, comparable with LOCK(mutex)? […]

    This seems like a brain dump and I can’t figure out the suggestion. Is it to rename one macro or rename two macros?

    The point of this PR is to be a fallback if #19865 is rejected. #19865 says there should only be one assert: AssertLockHeld, and you should never use it unless you need to call a EXCLUSIVE_LOCKS_REQUIRED function and the compiler doesn’t know the mutex is locked, and you can’t annotate the current function.

    Because there has been pushback against #19865, this PR keeps both asserts, but makes them more consistent with each other and chooses names that contrasts the stronger, preferred assert with the weaker, less-preferred assert.

    re: #19918 (review)

    In non-debug build a code like:

    Thanks for pointing it out, I added a note. To be sure, though, your build is different different from my build, and different from the CI builds used to verify changes.


    ajtowns commented at 10:53 pm on September 14, 2020:

    This seems like a brain dump and I can’t figure out the suggestion. Is it to rename one macro or rename two macros?

    Just to rename “WeaklyAssertLockHeld” to “LOCK_ALREADY_HELD” or similar.

    I don’t think it’s accurate to say one is “less-preferred” to the other – they do different things, and are appropriate in different circumstances. Hopefully the circumstances where WeaklyAssertLockHeld is appropriate are more rare, is all.

    “Assert that a mutex was already locked in any possible way this code could be reached. If DEBUG_LOCKORDER is defined, a runtime check that the mutex was actually locked by this thread will be made.”

    was a suggestion regarding the code docs, since it only has any runtime effect when DEBUG_LOCKORDER is defined.


    aaronpuchert commented at 10:04 pm on September 16, 2020:

    Note that ASSERT_EXCLUSIVE_LOCK has slightly weird scoping behaviour […]

    This is unrelated to scopes, the capability is assumed to be held after the assertion, regardless of whether we leave any scopes. (Think about it, there is no destructor for the assertion, so why would the scope ending change anything?)

    This analysis works on the source-level CFG. We can inspect this by passing --analyze -Xanalyzer -analyzer-checker=debug.DumpCFG to Clang. For the first example (using the vocabulary from the documentation):

     0 [B4 (ENTRY)]
     1   Succs (1): B3
     2
     3 [B1]
     4   1: x
     5   2: ++[B1.1]
     6   Preds (2): B2 B3(Unreachable)
     7   Succs (1): B0
     8
     9 [B2]
    10   1: m
    11   2: [B2.1].AssertHeld
    12   3: [B2.2]()
    13   Preds (1): B3
    14   Succs (1): B1
    15
    16 [B3]
    17   1: 1
    18   2: [B3.1] (ImplicitCastExpr, IntegralToBoolean, _Bool)
    19   T: if [B3.2]
    20   Preds (1): B4
    21   Succs (2): B2 B1(Unreachable)
    22
    23 [B0 (EXIT)]
    24   Preds (1): B1
    

    The if is in B3 and branches on a compile-time constant, thus we see that the branch to B1 (where the increment happens) is unreachable. In your second example the branch condition is no longer a compile-time constant. (Try adding const or constexpr, then it should work.)

    This is because ASSERT_EXCLUSIVE_LOCK tells the compiler we are going to check, but we actually don’t check (in non-debug build).

    Using ASSERT_EXCLUSIVE_LOCK even though you don’t always check is fine. It would be strange if it wasn’t, because that’s how the standard assert behaves.

    Maybe remove ASSERT_EXCLUSIVE_LOCK in non-debug builds, or at least clearly explain in the comment the dangers of using this.

    Having static analysis depend on the build profile doesn’t really make sense IMO. If you don’t have the same annotations in all profiles you’re just going to make your life harder.


    ryanofsky commented at 6:34 pm on September 17, 2020:

    re: #19918 (review)

    Just to rename “WeaklyAssertLockHeld” to “LOCK_ALREADY_HELD” or similar.

    I’m still not understanding why this is a good idea, but I made a space for it https://github.com/bitcoin-core/bitcoin-devwiki/wiki/AssertLockHeld-PRs

  9. ajtowns commented at 6:06 pm on September 8, 2020: member
    Concept ACK
  10. ajtowns commented at 6:11 pm on September 8, 2020: member

    This PR is an alternative to #19865. I still think #19865 is a better approach would prefer it.

    I think there’s two separate issues, (1) naming/behaviour for “we can’t prove to the compiler this is correct, so we’ll just tell it to trust us” and (2) “do we need to manually add code for runtime checks that just duplicate the compile time checks?”. I think this improves (1) and #19685 is mostly about (2), and that it makes sense to keep them separate. YMMV.

  11. MarcoFalke removed the label Docs on Sep 8, 2020
  12. MarcoFalke removed the label P2P on Sep 8, 2020
  13. MarcoFalke added the label Utils/log/libs on Sep 8, 2020
  14. in src/sync.h:84 in 070803dc7e outdated
    81+
    82+/**
    83+ * Assert at compile time and run time that a mutex is locked. Has no effect
    84+ * when EXCLUSIVE_LOCKS_REQUIRED annotations are enforced because the runtime
    85+ * assertions will never trigger (analogous to asserting an unsigned int is
    86+ * greator or equal to 0).
    


    vasild commented at 7:50 am on September 14, 2020:

    The compile time check is not an assertion (like static_assert), but is a warning. The code will get compiled with it if --enable-werror is not used during ./configure. Maybe reword to:

    Produce a compilation warning and assert at run time (only if DEBUG_LOCKORDER is defined) that a mutex is locked.


    ryanofsky commented at 8:23 pm on September 14, 2020:

    re: #19918 (review)

    The compile time check is not an assertion (like static_assert), but is a warning.

    Thanks, on CI these trigger fatal build errors and that seems like the most important thing, but I added a note about varying build behavior.

  15. in src/sync.h:100 in 070803dc7e outdated
     97+ * EXCLUSIVE_LOCKS_REQUIRED errors when the compiler can't determine that a
     98+ * mutex is locked.
     99+ */
    100+#define WeaklyAssertLockHeld(mutex) [&]() ASSERT_EXCLUSIVE_LOCK(mutex) { AssertLockHeldInternal(#mutex, __FILE__, __LINE__, &mutex); }()
    101+
    102+/** Assert at compile time and run time that a mutex is not locked. */
    


    vasild commented at 8:09 am on September 14, 2020:
    As above, maybe replace “assert at compile time” with “warn at compile time”?

    ryanofsky commented at 8:24 pm on September 14, 2020:

    re: #19918 (review)

    As above, maybe replace “assert at compile time” with “warn at compile time”?

    Thanks, added a note about build differences. Assert is in the name of the function and is the commonly used name for a correctness check which isn’t supposed to affect normal behavior, so I didn’t change the top description.

  16. ryanofsky force-pushed on Sep 14, 2020
  17. ryanofsky commented at 9:53 pm on September 14, 2020: member

    Updated 070803dc7e741c9d43b076b06d9540c6911ee427 -> 5c9eb2515a9e1d9ac58b29e5d8adb19748b39b17 (pr/lockb.1 -> pr/lockb.2, compare) with comment fixes


    re: #19918 (comment)

    LockAssertion was used (in a controversial way) in #19668 as it resolved problem.

    Yes, but the problem LockAssertion was solving in #19668 was a problem created by #19668 (changing AssertLockHeld to no longer be annotated with ASSERT_EXCLUSIVE_LOCK). Ever since LockAssertion was introduced in #14437 (as LockAnnotation) it has been redundant with AssertLockHeld, which first got the ASSERT_EXCLUSIVE_LOCK annotation in #13423.

  18. ryanofsky commented at 8:36 pm on September 17, 2020: member

    In IRC http://www.erisian.com.au/bitcoin-core-dev/log-2020-09-17.html#l-644, it was mentioned that WeaklyAssertLockHeld name is confusing. The name isn’t intended to be confusing, but it is intended to discourage use. If you are writing an assert you should always favor AssertLockHeld over WeaklyAssertLockHeld and only fall back when the compiler forces you to because it can’t prove that the mutex is locked in particular location.

    AssertLockHeld states that the lock is held with confidence, because the compiler can check that the statement is true at compile time. WeaklyAssertLockHeld makes the statement with less confidence because the compiler can’t check that it is true.

    Any case, https://github.com/bitcoin-core/bitcoin-devwiki/wiki/AssertLockHeld-PRs#disadvantages-of-2a-approach has a table of possible names where other suggestions can be added

  19. vasild commented at 10:58 am on September 18, 2020: member

    This looks good now except:

    • The confusing name WeaklyAssertLockHeld. It is confusing because you can’t weakly call abort() or semi-exit(). I think LOCK_ALREADY_HELD is better, already suggested.

    • The comments keep mentioning assert at compile time, already suggested.

  20. ryanofsky commented at 11:53 am on September 18, 2020: member

    It is confusing because you can’t weakly call abort() or semi-exit().

    This is really funny. The function is not called WeaklyAbort or WeaklyExit! It is called WeaklyAssert!

    Assert in english means to state or declare positively, “often forcefully or aggressively” like “The suspect continued to assert his innocence.” You can strongly assert something if that you are confident it is true, or you can weakly assert something if you are not confident. (Asserting has nothing to do with exiting in spoken english.)

    Anyway if there is another name you would prefer, please suggest it! There is a table of suggestions at https://github.com/bitcoin-core/bitcoin-devwiki/wiki/AssertLockHeld-PRs#disadvantages-of-2a-approach.

    LOCK_ALREADY_HELD makes no sense to me be because:

    • The LOCK_ALREADY_HELD name hides the fact that it’s an assert statement whose runtime behavior is identical to AssertLockHeld.
    • The LOCK_ALREADY_HELD name misleads you into thinking it may be a safer alternative to AssertLockHeld because it doesn’t contain the word assert, when actually it is a more dangerous alternative. (Compiler can prove that AssertLockHeld will not trigger, but compiler has no way of knowing whether an LOCK_ALREADY_HELD will trigger)
    • I haven’t seen anyone give a positive explanation why LOCK_ALREADY_HELD/AssertLockHeld is a good pairing of names for two assert statements that do the same thing, one with more compile time checking, one with less. I haven’t seen any explanation of why the pairing of names makes sense for a different reason either. All I’ve seen are claims that other pairs of names are confusing, not that LOCK_ALREADY_HELD/AssertLockHeld is good or has any coherent logic
  21. aaronpuchert commented at 12:19 pm on September 18, 2020: none
    FWIW, I also think “weakly” is something I wouldn’t know how to interpret into this context. I’ve added a suggestion {Proven,Unproven}AssertLockHeld that isn’t perfect but goes into a direction that I find worth exploring: one is a proven assertion (you could say a theorem) and the other an unproven assertion (you could say a conjecture or maybe axiom).
  22. ryanofsky commented at 12:30 pm on September 18, 2020: member

    I’ve added a suggestion {Proven,Unproven}AssertLockHeld that isn’t perfect but goes into a direction that I find worth exploring: one is a proven assertion (you could say a theorem) and the other an unproven assertion (you could say a conjecture or maybe axiom).

    Nice. I like UnprovenAssertLockHeld. Maybe UnsafelyAssertLockHeld would work too.

  23. vasild commented at 2:52 pm on September 18, 2020: member

    Just to mention that, given that #19970 and #19918 overlap, I think #19918 (this PR) is better (if the weak name is changed).

    My preference is for: FORCE_THE_COMPILER_TO_THINK_THAT_WE_OWN_THE_MUTEX_AND_ASSERT_AT_RUNTIME_IF_WE_DONT(), it would discourage usage, right?

  24. ryanofsky commented at 3:28 pm on September 18, 2020: member

    Just to mention that, given that #19970 and #19918 overlap, I think #19918 (this PR) is better (if the weak name is changed).

    My preference is for: FORCE_THE_COMPILER_TO_THINK_THAT_WE_OWN_THE_MUTEX_AND_ASSERT_AT_RUNTIME_IF_WE_DONT(), it would discourage usage, right?

    Sure, I assume that is a joke suggestion, but I am happy with all the alternate suggested pairs in https://github.com/bitcoin-core/bitcoin-devwiki/wiki/AssertLockHeld-PRs#disadvantages-of-2a-approach table except LOCK_ASSERTION/AssertLockHeld and LOCK_ALREADY_HELD/AssertLock because these pairs do not indicate which assert in the pair is the safer stronger preferred assert.

    I’d welcome adding more suggested pairs to the table. If #19865 is rejected and closed, we can do a poll for which of those pairs is most popular and update this PR with the decision.

    I am still holding out hope for #19865, though. Personally I’ve found compile time thread safety checking useful, and thread sanitizer checking useful, and debug_lockorder checking useful, and even found AssertLockHeld useful before it had the EXCLUSIVE_LOCK annotation. But now that it has an annotation proving it won’t trigger at runtime, I don’t see personally see the utility anymore.

  25. ajtowns commented at 6:34 am on September 19, 2020: member

    AssertLockHeld states that the lock is held with confidence, because the compiler can check that the statement is true at compile time. WeaklyAssertLockHeld makes the statement with less confidence because the compiler can’t check that it is true.

    From the perspective of the person writing the code, this seems exactly backwards: if you’re not getting compile time checks, and have disabled runtime checks in non-debug builds, you want to be extremely confident that the assertion is correct before relying on it in following code, so the WeaklyAssertLockHeld are actually the strongest assertions you’re making.

    I think the right analogy for LockAssertion isn’t to LOCK or to AssertLockAlreadyHeld (despite the implementation details) but actually to EXCLUSIVE_LOCKS_REQUIRED – in every place where we want to use LockAssertion we’d much rather use an EXCLUSIVE_LOCKS_REQUIRED annotation, but for whatever reason are prevented from that. So how about ASSERT_EXCLUSIVE_LOCK_REQUIREMENT_SATISFIED(cs_main) or something similar based on the function annotation we’d like to have, and changing the developer-notes recommendation along the lines of:

    When unable to add an EXCLUSIVE_LOCKS_REQUIRED annotation (eg, due to passing a lambda that uses a lock via a generic function that can’t require it), use ASSERT_EXCLUSIVE_LOCK_REQUIREMENT_SATISFIED(cs) at the start of the function to indicate to the compiler that lock correctness has been manually verified. In debug builds (with DEBUG_LOCKORDER set) this will be checked at runtime.

    I think that makes it pretty obvious that ASSERT_EXCLUSIVE_LOCK_REQUIREMENT_SATISFIED is not the preferred thing to do when the alternative is possible, and I think having it at the start of a function minimises any potential leakage that might happen due to weird code paths and also makes it easy to move it to a compile-time-enforced annotation if that becomes possible.

  26. ryanofsky commented at 11:48 am on September 19, 2020: member

    re: #19918 (comment)

    Sure, I’m saying weak=unprovable and strong=provable, and you’re saying actually strong=unprovable, and weak=provable. I think it’s overthinking a little, but very neat, and I’m happy to use any names.

    After names are chosen, everything else in this approach is pretty simple. It does have two asserts, so it isn’t quite as simple as #19865 or #19979 where there is only one assert. But it’s easy to always favor the provable assert, and fall back to the unprovable one when analysis doesn’t accept it. If analysis is turned off, both asserts are identical.

  27. ryanofsky commented at 12:11 pm on September 19, 2020: member
    After tough work getting table not to horizontally scroll I added ASSERT_EXCLUSIVE_LOCK_REQUIREMENT_SATISFIED to table of suggested names in https://github.com/bitcoin-core/bitcoin-devwiki/wiki/AssertLockHeld-PRs#disadvantages-of-2a-approach
  28. DrahtBot commented at 1:43 pm on September 19, 2020: member

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

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #19979 (Use proper TSA attributes (attempt two) by hebasto)
    • #19970 (sync.h: fix LockAssertion error reporting by ajtowns)
    • #19865 (scripted-diff: Restore AssertLockHeld after #19668, remove LockAssertion 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.

  29. ryanofsky renamed this:
    sync: Replace LockAssertion with WeaklyAssertLockHeld
    sync: Replace LockAssertion with AssertLockHeldUnverified
    on Sep 21, 2020
  30. ryanofsky force-pushed on Sep 21, 2020
  31. ryanofsky commented at 5:05 am on September 21, 2020: member
    Strongly updated 5c9eb2515a9e1d9ac58b29e5d8adb19748b39b17 -> 3f8f78f135d9e52f586e2a1a8af9899612eff5e3 (pr/lockb.2 -> pr/lockb.3, compare). Just a few changes to wording to address some concerns.
  32. vasild approved
  33. vasild commented at 1:03 pm on September 21, 2020: member

    ACK 3f8f78f13

    This looks good and is an improvement over master (thus ACK). It overlaps with #19979 which I think is a better alternative because it leaves just one assert method.

    “If you can’t figure a good name for a function then something’s wrong with that function.”

  34. ryanofsky commented at 2:30 pm on September 21, 2020: member

    @vasild, I don’t understand the way you are looking at the ASSERT_EXCLUSIVE_LOCK function (regardless of which name you would choose for the function). You seem to believe according to your comments here and in #19979#pullrequestreview-492559322 that ASSERT_EXCLUSIVE_LOCK is less preferable to NO_THREAD_SAFETY_ANALYSIS because ASSERT_EXCLUSIVE_LOCK is “extorting the compiler”.

    This sounds to me like saying if a seatbelt doesn’t fit you, instead of using a seatbelt extender, you should not wear a seatbelt, because using a seatbelt extender would be extorting the seatbelt.

    I think this PR is using ASSERT_EXCLUSIVE_LOCK exactly the way it’s intended to be used: to inform compiler thread analysis that a mutex is locked in cases where static analysis can’t prove that it’s locked. Do you believe this PR is misusing ASSERT_EXCLUSIVE_LOCK? Or maybe that ASSERT_EXCLUSIVE_LOCK is never acceptable to use? Why would giving the analysis (and giving developers reading the code) information be less preferable to disabling the analysis?

  35. vasild commented at 9:08 am on September 23, 2020: member

    You seem to believe … that ASSERT_EXCLUSIVE_LOCK is less preferable to NO_THREAD_SAFETY_ANALYSIS

    No, I believe [having two assert functions] is less preferable to [one assert function + NO_THREAD_SAFETY_ANALYSIS in some exceptional places].

    Overall I think that the most important thing is to have a clean interface (whatever is exported by sync.h) - one that is impossible to misuse and does not require mentions in developer-notes or long comments in the code. That means having just one function to “assert that the mutex is held”. Even if that has some limitations and in a few cases we need to use NO_THREAD_SAFETY_ANALYSIS or tweaks like in #19979.

    I think that this sole function should be tagged with ASSERT_EXCLUSIVE_LOCK because it best describes what the function does.

    I think that tagging it with EXCLUSIVE_LOCKS_REQUIRED is incorrect to some extent because internally the assert function does not do anything that requires holding the mutex (like accessing variables protected by that mutex). I.e. it can perform the checks correctly (no races would occur) without the mutex being held. However EXCLUSIVE_LOCKS_REQUIRED provides stronger checks at compile time and also does not silence warnings in the code that follow it and also @aaronpuchert himself said it is ok to tag the assert function with EXCLUSIVE_LOCKS_REQUIRED, so I accept that.

    I think this PR is using ASSERT_EXCLUSIVE_LOCK exactly the way it’s intended to be used: to inform compiler thread analysis that a mutex is locked in cases where static analysis can’t prove that it’s locked. Do you believe this PR is misusing ASSERT_EXCLUSIVE_LOCK?

    No, this PR is using ASSERT_EXCLUSIVE_LOCK exactly as intended, as I say above, but it is using it on AssertLockHeld2() while still having AssertLockHeld1() tagged with another attribute. Two functions is what I think should be avoided.

  36. DrahtBot commented at 4:14 pm on September 23, 2020: member

    🐙 This pull request conflicts with the target branch and needs rebase.

    Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a “draft”.

  37. DrahtBot added the label Needs rebase on Sep 23, 2020
  38. MarcoFalke commented at 9:53 am on October 19, 2020: member
    Untitled png
  39. MarcoFalke commented at 1:42 pm on October 25, 2020: member
    Closing for now. Let me know if I should reopen
  40. MarcoFalke closed this on Oct 25, 2020

  41. DrahtBot locked this on Feb 15, 2022

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-07-03 10:13 UTC

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