Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iox-1750 Add Expects to cxx::expected::value() and get_error() #1754

Conversation

mossmaurice
Copy link
Contributor

@mossmaurice mossmaurice commented Oct 20, 2022

Pre-Review Checklist for the PR Author

  1. Code follows the coding style of CONTRIBUTING.md
  2. Tests follow the best practice for testing
  3. Changelog updated in the unreleased section including API breaking changes
  4. Branch follows the naming format (iox-123-this-is-a-branch)
  5. Commits messages are according to this guideline
  6. Update the PR title
    • Follow the same conventions as for commit messages
    • Link to the relevant issue
  7. Relevant issues are linked
  8. Add sensible notes for the reviewer
  9. All checks have passed (except task-list-completed)
  10. All touched (C/C++) source code files from iceoryx_hoofs are added to ./clang-tidy-diff-scans.txt
  11. Assign PR to reviewer

Notes for Reviewer

  • Add Expects to cxx::expected::value() and get_error()
  • Fix legacy coding rule and add two doxygen comments

Checklist for the PR Reviewer

  • Commits are properly organized and messages are according to the guideline
  • Code according to our coding style and naming conventions
  • Unit tests have been written for new behavior
  • Public API changes are documented via doxygen
  • Copyright owner are updated in the changed files
  • All touched (C/C++) source code files from iceoryx_hoofs have been added to ./clang-tidy-diff-scans.txt
  • PR title describes the changes

Post-review Checklist for the PR Author

  1. All open points are addressed and tracked via issues

References

@mossmaurice mossmaurice added the bugfix Solves a bug label Oct 20, 2022
@mossmaurice mossmaurice self-assigned this Oct 20, 2022
@codecov
Copy link

codecov bot commented Oct 20, 2022

Codecov Report

Merging #1754 (434d0ce) into master (8f6af2f) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #1754   +/-   ##
=======================================
  Coverage   77.37%   77.38%           
=======================================
  Files         366      366           
  Lines       14187    14196    +9     
  Branches     1983     1983           
=======================================
+ Hits        10977    10985    +8     
  Misses       2583     2583           
- Partials      627      628    +1     
Flag Coverage Δ
unittests 77.03% <100.00%> (+<0.01%) ⬆️
unittests_timing 15.70% <48.00%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...eoryx_hoofs/include/iceoryx_hoofs/cxx/expected.hpp 100.00% <ø> (ø)
...fs/include/iceoryx_hoofs/internal/cxx/expected.inl 98.34% <100.00%> (+0.13%) ⬆️
iceoryx_hoofs/source/concurrent/loffli.cpp 85.71% <0.00%> (-2.86%) ⬇️

Copy link
Contributor

@elfenpiff elfenpiff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mossmaurice the issue itself is based on a false assumption. Accessing a non existing value or error in an expected is defined behavior.
The underlying variant returns nullptr in get_type_at_index which is used in the expected implementation.

So accessing a non existing value or error is defined as dereferencing a nullptr.

The question which now remains: should we call the error handler and where. Since this is not a problem of the expected but the underlying variant I suggest to adjust the methods there. We could adjust get_type_at_index so that it does no longer return a nullptr when the type is not emplaced there but calls the error handler.

What do you think?

@elfenpiff elfenpiff removed the request for review from elBoberido October 20, 2022 09:53
@mossmaurice
Copy link
Contributor Author

mossmaurice commented Oct 20, 2022

the issue itself is based on a false assumption. Accessing a non existing value or error in an expected is defined behavior. The underlying variant returns nullptr in get_type_at_index which is used in the expected implementation.

So accessing a non existing value or error is defined as dereferencing a nullptr.

The question which now remains: should we call the error handler and where. Since this is not a problem of the expected but the underlying variant I suggest to adjust the methods there. We could adjust get_type_at_index so that it does no longer return a nullptr when the type is not emplaced there but calls the error handler.

What do you think?

@elfenpiff

I was thinking about this before. Looking at the STL API of std::variant I came to the conclusion, that returning a nullptr and putting the burden on the user to check it, is the best we can do. std::variant uses an overloaded std::get method which throws an exception in the error case. We also do use nullptr in other places like container::vector::data() or memory::unique_ptr::get().

In this particular case, in my opinion it's not the task of the variant to check the validity but the task of the user. In this case the user is the expected and this class has the burden to check if the underlying variant can safely be accessed. By using Expects the error handler is then called in the expected.

Let's say the following would be defined behaviour, which error would returned from get_error?

auto sut = expected<Foo, Bar>::create_value(VALID_VALUE);
auto foo = sut.get_error();

@mossmaurice mossmaurice force-pushed the iox-1750-add-expects-to-expected-value-and-get-error branch from 2c64a99 to 1b021b6 Compare October 20, 2022 15:03
@mossmaurice mossmaurice requested a review from elfenpiff October 20, 2022 15:03
@mossmaurice mossmaurice force-pushed the iox-1750-add-expects-to-expected-value-and-get-error branch 4 times, most recently from f79b662 to f72002d Compare October 20, 2022 15:27
@@ -55,6 +55,7 @@
- `m_originId` in `mepoo::ChunkHeader` sometimes not set [\#1668](https://github.com/eclipse-iceoryx/iceoryx/issues/1668)
- Removed `cxx::unique_ptr::reset` [\#1655](https://github.com/eclipse-iceoryx/iceoryx/issues/1655)
- CI uses outdated clang-format [\#1736](https://github.com/eclipse-iceoryx/iceoryx/issues/1736)
- Avoid UB when accessing `iox::expected` [\#1750](https://github.com/eclipse-iceoryx/iceoryx/issues/1750)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement is wrong, there is currently no undefined behavior in the expected since the variant returns a nullptr in those cases which is well defined.
But an expect call before hand makes sense so that we can forward this to some kind of error handling.

Copy link
Contributor Author

@mossmaurice mossmaurice Oct 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elfenpiff I don't fully get what you mean. The following is definitely UB and avoided with this PR:

auto sut = expected<Foo, Bar>::create_error(Bar::VALID_ERROR);
auto myValue = sut->memberVariableOfFoo;

Because as you wrote the ìox::variant will return a nullptr which cause UB in operator->.

@@ -239,21 +243,22 @@ class IOX_NO_DISCARD expected<ErrorType> : public FunctionalInterface<expected<E
bool has_error() const noexcept;

/// @brief returns a reference to the contained error value, if the expected
/// does not contain an error this is undefined behavior
/// does not contain an error the application terminates
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this wrong in detail. I would rather state that the error handler will be called and then it does what an error handler does. Please adjust this here and in the other descriptions.

Copy link
Contributor Author

@mossmaurice mossmaurice Oct 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently use this wording in most of the classes e.g. iox::optional, iox::vector, so I followed along for consistency. But I know what you mean, hence adjusted the wording. The doxygen of the other classes should be adapted with #1032.

@mossmaurice mossmaurice force-pushed the iox-1750-add-expects-to-expected-value-and-get-error branch from f72002d to d724cbe Compare October 25, 2022 21:41
@mossmaurice mossmaurice force-pushed the iox-1750-add-expects-to-expected-value-and-get-error branch from d724cbe to 4f51307 Compare October 25, 2022 21:45
@mossmaurice mossmaurice force-pushed the iox-1750-add-expects-to-expected-value-and-get-error branch from 4f51307 to 434d0ce Compare October 26, 2022 08:13
@mossmaurice mossmaurice merged commit 3aecfb8 into eclipse-iceoryx:master Oct 26, 2022
@mossmaurice mossmaurice deleted the iox-1750-add-expects-to-expected-value-and-get-error branch October 26, 2022 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix Solves a bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Accessing cxx::expected which contains a value or error leads to UB if the contrary is accessed
3 participants