Skip to content

C++: Improve documentation for cpp/iterator-to-expired-container #16367

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

Conversation

MathiasVP
Copy link
Contributor

This PR does two things that should hopefully make the results from the new cpp/iterator-to-expired-container query easier to understand:

  • It updates the alert message to more correctly reflect what's going on
  • It updates the qhelp file so that it contains an example of a fix.

Note that, because of the first fix, we only get half the number of alerts since we no longer include the call to begin in the alert message. Previously, we'd often get an alert on the same location with two alert messages such as:

  • This object is destroyed before call to begin is called.
  • This object is destroyed before call to end is called.

Other than the alert being wrong, it was also quite annoying to have two alerts on the same element explaining the same problem.

@MathiasVP MathiasVP requested a review from a team as a code owner April 30, 2024 15:36
@MathiasVP MathiasVP requested a review from geoffw0 April 30, 2024 15:36
@MathiasVP MathiasVP added the no-change-note-required This PR does not need a change note label Apr 30, 2024
Copy link
Contributor

github-actions bot commented Apr 30, 2024

QHelp previews:

cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp

Iterator to expired container

Using an iterator owned by a container after the lifetime of the container has expired can lead to undefined behavior. This is because the iterator may be invalidated when the container is destroyed, and dereferencing an invalidated iterator is undefined behavior. These problems can be hard to spot due to C++'s complex rules for temporary object lifetimes and their extensions.

Recommendation

Never create an iterator to a temporary container when the iterator is expected to be used after the container's lifetime has expired.

Example

The rules for lifetime extension ensures that the code in lifetime_of_temp_extended is well-defined. This is because the lifetime of the temporary container returned by get_vector is extended to the end of the loop. However, prior to C++23, the lifetime extension rules do not ensure that the container returned by get_vector is extended in lifetime_of_temp_not_extended. This is because the temporary container is not bound to a rvalue reference.

#include <vector>

std::vector<int> get_vector();

void use(int);

void lifetime_of_temp_extended() {
  for(auto x : get_vector()) {
    use(x); // GOOD: The lifetime of the vector returned by `get_vector()` is extended until the end of the loop.
  }
}

// Writes the the values of `v` to an external log and returns it unchanged.
const std::vector<int>& log_and_return_argument(const std::vector<int>& v);

void lifetime_of_temp_not_extended() {
  for(auto x : log_and_return_argument(get_vector())) {
    use(x); // BAD: The lifetime of the vector returned by `get_vector()` is not extended, and the behavior is undefined.
  }
}

To fix lifetime_of_temp_not_extended, consider rewriting the code so that the lifetime of the temporary object is extended. In fixed_lifetime_of_temp_not_extended, the lifetime of the temporary object has been extended by storing it in an rvalue reference.

void fixed_lifetime_of_temp_not_extended() {
  auto&& v = get_vector();
  for(auto x : log_and_return_argument(v)) {
    use(x); // GOOD: The lifetime of the container returned by `get_vector()` has been extended to the lifetime of `v`.
  }
}

References

geoffw0
geoffw0 previously approved these changes Apr 30, 2024
Copy link
Contributor

@geoffw0 geoffw0 left a comment

Choose a reason for hiding this comment

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

Changes LGTM.

Is it worth getting a docs review for this small change? Come to think of it, did the .qhelp for this new query get a full review at some point?

@MathiasVP
Copy link
Contributor Author

Is it worth getting a docs review for this small change?

Hm, yeah. That may be a good idea. I'll add a ready-for-docs-review label to this PR

Come to think of it, did the .qhelp for this new query get a full review at some point?

It did get a review when we merged it into experimental, yes: #15939

@MathiasVP MathiasVP added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Apr 30, 2024
@mchammer01 mchammer01 self-requested a review May 1, 2024 10:33
mchammer01
mchammer01 previously approved these changes May 1, 2024
Copy link
Contributor

@mchammer01 mchammer01 left a comment

Choose a reason for hiding this comment

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

LGTM ✨
Two very minor suggestions from a Docs perspective.

@MathiasVP MathiasVP dismissed stale reviews from mchammer01 and geoffw0 via 22e843a May 1, 2024 10:41
MathiasVP and others added 2 commits May 1, 2024 11:41
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
@MathiasVP
Copy link
Contributor Author

Thanks @mchammer01 🙇 All comments addressed!

Copy link
Contributor

@mchammer01 mchammer01 left a comment

Choose a reason for hiding this comment

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

LGTM :shipit:

@MathiasVP MathiasVP merged commit dc4604f into github:main May 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C++ documentation no-change-note-required This PR does not need a change note ready-for-doc-review This PR requires and is ready for review from the GitHub docs team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants