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

Matcher combination does not work outside macro call #2777

Closed
gonzaponte opened this issue Dec 8, 2023 · 5 comments
Closed

Matcher combination does not work outside macro call #2777

gonzaponte opened this issue Dec 8, 2023 · 5 comments

Comments

@gonzaponte
Copy link

Describe the bug
Matchers (at least floating point matchers) cannot be combined outside of a macro call.

Expected behavior
To be able to combine matchers arbitrarily and use them in a macro.

Reproduction steps
Given the following two definitions

auto is_close_to_zero = WithinAbs(0, 2e-2);
auto is_zero          = WithinULP(0., 1);

I can combine them in the macro like

CHECK_THAT(a_value, is_close_to_zero && ! is_zero);

but not outside of the macro like

auto is_close_to_but_not_zero = is_close_to_zero && ! is_zero;
CHECK_THAT(a_value, is_close_to_but_not_zero);

The latter gives a segfault.

Platform information:

  • OS: Ubuntu 20.04
  • Compiler+version: clang 16.0.1
  • Catch version: v3.3.2

Additional context
None

@horenmar
Copy link
Member

horenmar commented Dec 8, 2023

I assume you found the part of docs that says

IMPORTANT: The combining operators do not take ownership of the matcher objects being combined. This means that if you store combined matcher object, you have to ensure that the matchers being combined outlive its last use. What this means is that the following code leads to a use-after-free (UAF):

since you have the matchers live in their own vars. Note that ! also counts as combination operator for this purpose.

@gonzaponte
Copy link
Author

Yes, I had read that. After some more thought, I think I misinterpreted that note.
I was assuming that the lifetime referred only to the initial matchers, not to every intermediate combination. So in

auto is_close_to_but_not_zero = is_close_to_zero && ! is_zero;

! is_zero leads to UAF because it's freed immediately after that line while in

auto is_not_zero = ! is_zero;
auto is_close_to_but_not_zero = is_close_to_zero && is_not_zero;

it is still in scope. Am I interpreting it correctly?

@horenmar
Copy link
Member

horenmar commented Dec 8, 2023

Yes.

!is_zero creates a temporary of type MatchNotOf<double> that references the original is_zero matcher. && creates a MatchAllOf<double> that references this temporary and that then leads to UAF.

@gonzaponte
Copy link
Author

Understood. Thanks and apologies for the noise.

@horenmar
Copy link
Member

horenmar commented Dec 9, 2023

No problem. I'll probably add more examples to the docs to make this clearer.

horenmar added a commit that referenced this issue Dec 13, 2023
horenmar added a commit that referenced this issue Dec 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants