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

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

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.

@github github deleted a comment from github-actions bot Nov 27, 2023
@github github deleted a comment from github-actions bot Nov 27, 2023
@github github deleted a comment from github-actions bot Nov 28, 2023
Copy link
Contributor

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. However, if the std::string object is destroyed, then 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 convert 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*);

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*);

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.

@@ -0,0 +1,7 @@
#include <string>
void work(const char*);

Copy link
Contributor

Choose a reason for hiding this comment

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

We normally include a comment here. Something like this, but I'm sure you can write this more clearly:

Suggested change
// BAD: `c_str` is destroyed on return so `work` acts on a pointer to invalid memory

@@ -0,0 +1,7 @@
#include <string>
void work(const char*);

Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, we should add a GOOD comment here.

Co-authored-by: Felicity Chapman <felicitymay@github.com>
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.

None yet

4 participants