This is an archive of the discontinued LLVM Phabricator instance.

[libc++] add basic runtime assertions to <latch>
ClosedPublic

Authored by diamante0018 on Jul 4 2023, 2:43 AM.

Details

Reviewers
ldionne
Group Reviewers
Restricted Project
Commits
rG5e807c38bf9b: [libc++] add basic runtime assertions to <latch>
Summary

Adding assertions will aid users that have bugs in their code to receive better error messages.

Diff Detail

Event Timeline

diamante0018 created this revision.Jul 4 2023, 2:43 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 4 2023, 2:43 AM
diamante0018 requested review of this revision.Jul 4 2023, 2:43 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 4 2023, 2:43 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript

I have undone an unrelated code formatting change.

diamante0018 updated this revision to Diff 537014.EditedJul 4 2023, 2:51 AM

I am learning how to use this differential tool and it appears the previous patch undid the changes I actually intended to commit instead of removing just the "one" offending line in regards to unrelated formatting changes.
I should have fixed the issue and now the actual diff file should be complete.
Sorry

diamante0018 edited the summary of this revision. (Show Details)Jul 4 2023, 4:28 AM
ldionne requested changes to this revision.Jul 4 2023, 12:03 PM

Thanks for the patch! If you upload the patch with arc, it should also include some context in the diff, which is useful. Let us know if you run into issues with that.

libcxx/include/latch
75

Not attached: Can you please add some tests for these assertions? To see how we do this for other assertions: libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp.

80–81

I think it is also UB if __expected > max(), right? If so, let's add an assertion.

91–92

I read:

If n is greater than the value of the internal counter or is negative, the behavior is undefined.

So we can actually check more than just __update >= 0.

112–113

Same here:

If n is greater than the value of the internal counter or is negative, the behavior is undefined.

This revision now requires changes to proceed.Jul 4 2023, 12:03 PM
diamante0018 added inline comments.Jul 4 2023, 12:35 PM
libcxx/include/latch
80–81

You are right but in this implementation because max is equivalent to std::numeric_limits<ptrdiff_t>::max() it should not be possible

ldionne added inline comments.Jul 4 2023, 1:28 PM
libcxx/include/latch
80–81

Then the compiler can probably elide the check, but we should still have the check!

diamante0018 updated this revision to Diff 537166.EditedJul 4 2023, 1:28 PM
diamante0018 edited the summary of this revision. (Show Details)

I addressed the review.

Please note the following:
Because in the llvm's implementation max() returns the max value of ptrdiff_t" (numeric_limits<ptrdiff_t>::max();) It should not be possible to check for that in an assertion.

Note that I used memory_order_relaxed in the assertions as that seems to be the memory order that has the potential to cause less collateral damage. Let me know if it's fine please.

Thanks

diamante0018 added inline comments.Jul 4 2023, 1:30 PM
libcxx/include/latch
80–81

I see, I just saw your comment. I will add the check right away.

Added an assertions to check that when the latch object is constructed "n" is not greater than max

diamante0018 added inline comments.Jul 4 2023, 1:36 PM
libcxx/include/latch
80–81

I added the check. That should be the last point to address from your previous review. I hope all is good now. Thanks 🐱

I added the check for "n is greater than max()". That should be the last point to address from your previous review. I hope all is good now. Thanks 🐱

diamante0018 marked 5 inline comments as done.Jul 4 2023, 1:59 PM
ldionne added inline comments.Jul 4 2023, 2:17 PM
libcxx/include/latch
95–99

Could we instead move the _LIBCPP_ASSERT after the fetch_sub, i.e. do:

_LIBCPP_ASSERT_UNCATEGORIZED(
            __update >= 0, "latch::count_down called with a negative value");
auto const __old = __a_.fetch_sub(__update, memory_order_release);
_LIBCPP_ASSERT_UNCATEGORIZED(
            __update > __old,
            "__update is greater than the value of the internal counter");

This would not require an additional atomic load, yet we would catch that we just did something really really bad (i.e. that __a_ is now negative and who knows what will happen next).

libcxx/test/libcxx/thread/thread.latch/assert.arrive_and_wait.pass.cpp
2

Let's also add a assert.ctor.pass.cpp test to test the assertion you added in the constructor!

Added ctor unit test.
Correct assertion placement.
Remove one assertion as I realized that immediately after we are calling a function with the same kind of assertion. So perhaps it's not worth it to call .load() to check for the internal counter when we have a similar test right after that is checked without calling any extra operations

diamante0018 marked an inline comment as done.Jul 4 2023, 11:30 PM

I am a bit concerned about these new tests apparently failing because I, unfortunately, I don't know why they are failing despite me checking them over and over again for mistakes. I need to learn all of this.

diamante0018 marked an inline comment as done.Jul 4 2023, 11:30 PM

I realized by looking at already existing tests that my ctor.pass is incorrect. I will try to fix it in a few hours

Correct the tests files (hopefully)

Correct syntax in a test cpp file

Make sure the tests messages match the assertions messages from libcxx (should fix the tests)

Fix logic in the assertions I added

Add // class latch comment to all test files

Fix the test

ldionne added inline comments.Jul 5 2023, 5:51 AM
libcxx/include/latch
117–118

To avoid being inconsistent, I think I would remove this assertion and add a comment saying // preconditions on __update are checked in count_down().

libcxx/test/libcxx/thread/thread.latch/assert.ctor.pass.cpp
34

You should do this instead:

TEST_LIBCPP_ASSERT_FAILURE([]{ std::latch foo(-1); }(), "assertion message");
// and add a comment that we can't check the precondition for max() because there's no value that would violate the precondition (in our implementation)

Address review

diamante0018 marked 2 inline comments as done.Jul 5 2023, 6:19 AM

Hopefully, that should do it. I am happy I made progress with these tests earlier today. Was a bit hard to figure out but now they should turn green.

Apply clang-format on the lambda function

Fix format of my patch

Update tests

Fix logic in my assertions

Change "<" to "<=" in assert call

Test CI finally turned green woot woot. Thanks @Idionne 🥳

ldionne accepted this revision.Jul 5 2023, 2:17 PM

LGTM, thanks! If you need someone to commit this on your behalf, please let us know Author Name <email@domain> to use for attribution.

This revision is now accepted and ready to land.Jul 5 2023, 2:17 PM
diamante0018 added a comment.EditedJul 5 2023, 2:18 PM

Yes please:

Edoardo Sanguineti edoardo.sanguineti222@gmail.com

Thanks again

Thank *you* for the patch!