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

fix: avoid use-after-move StatusOr #7635

Merged
merged 3 commits into from
Nov 19, 2021

Conversation

devjgm
Copy link
Contributor

@devjgm devjgm commented Nov 19, 2021

Similar to: #7588

This code allowed callers to (rightfully) move-out the StatusOr that
was held in current_. Therefore, it's a bug if we then consult the
status of current_.ok(), because it may be in a moved-from state.

The fix is to track the current_ok_ bit separately, so that we only
ever assign to current_ and never read it after it could have been
moved.


This change is Reviewable

@devjgm devjgm requested a review from a team as a code owner November 19, 2021 15:21
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Nov 19, 2021
@google-cloud-cpp-bot
Copy link
Collaborator

Google Cloud Build Logs
For commit: eb6f5e13609a7a875c24f869b452873921979b17

ℹ️ NOTE: Kokoro logs are linked from "Details" below.

@codecov
Copy link

codecov bot commented Nov 19, 2021

Codecov Report

Merging #7635 (8477b5f) into main (72a9ed2) will decrease coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #7635      +/-   ##
==========================================
- Coverage   95.28%   95.27%   -0.01%     
==========================================
  Files        1251     1251              
  Lines      112992   112994       +2     
==========================================
- Hits       107659   107653       -6     
- Misses       5333     5341       +8     
Impacted Files Coverage Δ
google/cloud/stream_range.h 100.00% <100.00%> (ø)
google/cloud/storage/internal/curl_handle.h 80.00% <0.00%> (-2.86%) ⬇️
...bigtable/examples/bigtable_hello_instance_admin.cc 81.31% <0.00%> (-2.20%) ⬇️
google/cloud/bigtable/async_read_stream_test.cc 97.32% <0.00%> (-0.67%) ⬇️
.../cloud/storage/benchmarks/throughput_experiment.cc 74.37% <0.00%> (-0.51%) ⬇️
...cloud/pubsub/internal/subscription_session_test.cc 97.75% <0.00%> (-0.50%) ⬇️
...ud/spanner/integration_tests/client_stress_test.cc 86.18% <0.00%> (+0.65%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 72a9ed2...8477b5f. Read the comment docs.

@google-cloud-cpp-bot
Copy link
Collaborator

Google Cloud Build Logs
For commit: 1543f9603ce20061eabf933aab19a674a2a6f421

ℹ️ NOTE: Kokoro logs are linked from "Details" below.

@@ -186,6 +186,7 @@ class StreamRange {
};
auto v = reader_();
absl::visit(UnpackVariant{*this}, std::move(v));
current_ok_ = current_.ok();
Copy link
Contributor

Choose a reason for hiding this comment

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

This one is a little strange in the "received final OK" case, where UnpackVariant didn't assign to current_, so we are possibly looking at a move-from StatusOr. Not that that matters if ok() is defined in that state, but perhaps it would be nicer to just make the sr.current_ assignment unconditional.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good observation. I can't unconditionally assign to sr.current_, because it's not allowed to assign an OK Status to a StatusOr. However, I did change the code a bit to be clearer and more correct by moving the sr.current_ok_ assignment into the UnpackVariant functor, so it can set it correctly in each case. PTAL.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, sounds good.

Aside: In the bigger picture I still find the control flow confusing. For example, there are really only three states ...

    { => T } S1 [ => non-OK ] S2 [ => end ] S3

... but we currently use all four. To that end, I might make the initial state S1 ...

  bool current_ok_ = true;
  bool is_end_ = false;

and also stop S3 from ever calling reader_().

@coryan
Copy link
Contributor

coryan commented Nov 19, 2021

FWIW, you control StatusOr<T>. You can define what is the state of a moved-from StatusOr<T>. You could say (for example) that its .code() and .ok() values remain unchanged.

Similar to: googleapis#7588

This code allowed callers to (rightfully) move-out the `StatusOr` that
was held in `current_`. Therefore, it's a bug if we then consult the
status of `current_.ok()`, because it may be in a moved-from state.

The fix is to track the `current_ok_` bit separately, so that we only
ever assign to `current_` and never read it after it could have been
moved.
@google-cloud-cpp-bot
Copy link
Collaborator

Google Cloud Build Logs
For commit: 8477b5f5bedfc4e8437c64d6f6937203eb7b17ab

ℹ️ NOTE: Kokoro logs are linked from "Details" below.

@devjgm
Copy link
Contributor Author

devjgm commented Nov 19, 2021

FWIW, you control StatusOr<T>. You can define what is the state of a moved-from StatusOr<T>. You could say (for example) that its .code() and .ok() values remain unchanged.

True. I'd prefer to avoid defining specifically what the moved-from state is for Status or StatusOr, if possible. Especially, for non-OK situations where we'd be losing the message, payload, etc. If we need to reach for that tool, we can, but avoiding it seems preferable, IMO.

Plus, I have a PR right behind this one where preserving the code() would be difficult, but we can discuss that in the next PR.

@devjgm devjgm merged commit 202265a into googleapis:main Nov 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants