Skip to content

Avoid use-after-return caused by double move #11485

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tamird
Copy link
Contributor

@tamird tamird commented Jun 9, 2025

Summary:

Previously, Result<T>'s constructor used std::move(val) to initialize the
value. This resulted in an unnecessary extra move and destructor call on a
moved-from stack object, triggering an HWASAN stack tag mismatch when the
moved-from object was later destructed.

Replacing std::move(val) with std::forward<T>(val) avoids the extra move
while preserving correct semantics. This ensures only one move occurs and
avoids lifetime violations that can lead to tag mismatches under HWASAN.

Differential Revision: D76271359

Copy link

pytorch-bot bot commented Jun 9, 2025

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/11485

Note: Links to docs will display an error until the docs builds have been completed.

✅ No Failures

As of commit 2c6361e with merge base 611092d (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 9, 2025
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D76271359

@tamird
Copy link
Contributor Author

tamird commented Jun 9, 2025

@pytorchbot label "release notes: none"

@pytorch-bot pytorch-bot bot added the release notes: none Do not include this in the release notes label Jun 9, 2025
tamird pushed a commit to tamird/executorch that referenced this pull request Jun 9, 2025
Summary:

As described.

Differential Revision: D76271359
@tamird tamird force-pushed the export-D76271359 branch from 34b2f65 to 1062b13 Compare June 9, 2025 16:46
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D76271359

@tamird tamird force-pushed the export-D76271359 branch from 1062b13 to 6a843b6 Compare June 9, 2025 17:02
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D76271359

@tamird tamird changed the title Use std::forward to avoid immediate trivial move Avoid use-after-return caused by double move Jun 9, 2025
@tamird tamird force-pushed the export-D76271359 branch from 6a843b6 to fbbb9a7 Compare June 9, 2025 17:07
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D76271359

@tamird tamird force-pushed the export-D76271359 branch from fbbb9a7 to d9e7ea4 Compare June 9, 2025 17:08
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D76271359

Summary:
Previously, `Result<T>`'s constructor used `std::move(val)` to initialize the
value. This resulted in an unnecessary extra move and destructor call on a
moved-from stack object, triggering an HWASAN stack tag mismatch when the
moved-from object was later destructed.

Replacing `std::move(val)` with `std::forward<T>(val)` avoids the extra move
while preserving correct semantics. This ensures only one move occurs and
avoids lifetime violations that can lead to tag mismatches under HWASAN.

Reviewed By: StefanBossbaly

Differential Revision: D76271359
@tamird tamird force-pushed the export-D76271359 branch from d9e7ea4 to 2c6361e Compare June 9, 2025 17:41
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D76271359

Copy link
Contributor

@JacobSzwejbka JacobSzwejbka left a comment

Choose a reason for hiding this comment

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

Thanks for the catch!

/* implicit */ Result(T&& val) : value_(std::move(val)), hasValue_(true) {}
/// Value forwarding constructor.
/* implicit */ Result(T&& val)
: value_(std::forward<T>(val)), hasValue_(true) {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a test that wouldve caught the previous bad behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. Where are the tests for this type?

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

@swolchok swolchok left a comment

Choose a reason for hiding this comment

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

looks great, needs test, happy to accept with the test

@tamird
Copy link
Contributor Author

tamird commented Jun 9, 2025

looks great, needs test, happy to accept with the test

I tried writing a test, but I have failed to induce the problematic behavior. I think it shows up only in the presence of stack tagging as performed by hwasan.

Comment on lines -73 to +75
/// Value move constructor.
/* implicit */ Result(T&& val) : value_(std::move(val)), hasValue_(true) {}
/// Value forwarding constructor.
/* implicit */ Result(T&& val)
: value_(std::forward<T>(val)), hasValue_(true) {}
Copy link
Contributor

Choose a reason for hiding this comment

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

I misread what was going on here originally. This isn't a template function (though it is a member of a template class), so this really is an rvalue reference. I think that the original code is probably correct; std::forward is for arguments to template functions (https://en.cppreference.com/w/cpp/utility/forward.html).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported release notes: none Do not include this in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants