Skip to content

C++: Add a new query for calling c_str on temporary objects #14928

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

Merged
merged 11 commits into from
Nov 29, 2023

Conversation

MathiasVP
Copy link
Contributor

@MathiasVP MathiasVP commented Nov 27, 2023

This PR adds a new query that looks for variations of:

char* p = std::string("hello").c_str();
use(p);

MRVA results look really good. On the top 1000 projects I'm seeing 25 results, and they all look like TPs 🎉.

In the future I'd like to extend the query to support more lifetimes than just "temporary objects", but for now this is good enough, I think.

@MathiasVP MathiasVP force-pushed the surprising-lifetimes-c_str branch from d4ed5d6 to 78671a9 Compare November 27, 2023 22:26
@github github deleted a comment from github-actions bot Nov 27, 2023
@MathiasVP MathiasVP force-pushed the surprising-lifetimes-c_str branch from 78671a9 to 9c59094 Compare November 27, 2023 22:41
@github github deleted a comment from github-actions bot Nov 27, 2023
@MathiasVP MathiasVP force-pushed the surprising-lifetimes-c_str branch from 9c59094 to e10caa6 Compare November 28, 2023 09:14
@github github deleted a comment from github-actions bot Nov 28, 2023
Copy link
Contributor

github-actions bot commented Nov 28, 2023

QHelp previews:

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

Use of string after lifetime ends

Calling c_str on a std::string object returns a pointer to the underlying character array. When the std::string object is destroyed, the pointer returned by c_str is no longer valid. If the pointer is used after the std::string object is destroyed, then the behavior is undefined.

Recommendation

Ensure that the pointer returned by c_str does not outlive the underlying std::string object.

Example

The following example concatenates two std::string objects, and then converts the resulting string to a C string using c_str so that it can be passed to the work function. However, the underlying std::string object that represents the concatenated string is destroyed as soon as the call to c_str returns. This means that work is given a pointer to invalid memory.

#include <string>
void work(const char*);

// BAD: the concatenated string is deallocated when `c_str` returns. So `work`
// is given a pointer to invalid memory.
void work_with_combined_string_bad(std::string s1, std::string s2) {
  const char* combined_string = (s1 + s2).c_str();
  work(combined_string);
}

The following example fixes the above code by ensuring that the pointer returned by the call to c_str does not outlive the underlying std::string objects. This ensures that the pointer passed to work points to valid memory.

#include <string>
void work(const char*);

// GOOD: the concatenated string outlives the call to `work`. So the pointer
// obtainted from `c_str` is valid.
void work_with_combined_string_good(std::string s1, std::string s2) {
  auto combined_string = s1 + s2;
  work(combined_string.c_str());
}

References

@MathiasVP MathiasVP marked this pull request as ready for review November 28, 2023 09:18
@MathiasVP MathiasVP requested a review from a team as a code owner November 28, 2023 09:18
Copy link
Contributor

@jketema jketema left a comment

Choose a reason for hiding this comment

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

Two small comments for now.

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.

A couple of comments below.

Query, library changes, qhelp, test otherwise LGTM.

I'm looking at some real world results as well and will comment on those later.

@geoffw0
Copy link
Contributor

geoffw0 commented Nov 28, 2023

Real world results: I did a smaller MRVA run and tested on some local databases as well. Found two results, both LGTM. 👍

@geoffw0 geoffw0 added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Nov 28, 2023
@geoffw0
Copy link
Contributor

geoffw0 commented Nov 28, 2023

I'm happy with this PR and I think it's a great new query. Looks like @jketema is happy too. DCA LGTM. I think we just need the docs team to take a look (I've taken the liberty of adding the ready-for-doc-review label).

@jketema
Copy link
Contributor

jketema commented Nov 28, 2023

I haven't looked at all the details, but I trust @geoffw0's judgement here.

@MathiasVP
Copy link
Contributor Author

(I've taken the liberty of adding the ready-for-doc-review label).

Thank you. I was indeed going to do that as soon as I had gotten a 👍 from the team.

felicitymay
felicitymay previously approved these changes Nov 29, 2023
Copy link
Contributor

@felicitymay felicitymay 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 review request. This looks good. Just a couple of small comments.

Co-authored-by: Felicity Chapman <felicitymay@github.com>
Copy link
Contributor

@felicitymay felicitymay 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 text updates. All LGTM.

@MathiasVP
Copy link
Contributor Author

Coding Standards failure is unrelated. Merging! 🤠

@MathiasVP MathiasVP merged commit 1f9e2c7 into github:main Nov 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C++ documentation 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.

4 participants