-
Notifications
You must be signed in to change notification settings - Fork 446
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
[SDK] Fix core dump issue in OTEL_INTERNAL_LOG_DISPATCH macro #2394
Conversation
b2f2713
to
39c45a2
Compare
39c45a2
to
ca08c5a
Compare
Codecov Report
@@ Coverage Diff @@
## main #2394 +/- ##
=======================================
Coverage 87.43% 87.43%
=======================================
Files 199 199
Lines 6030 6030
=======================================
Hits 5272 5272
Misses 758 758
|
Thanks for the PR. Ideally |
std::stringstream tmp_stream; \ | ||
tmp_stream << message; \ | ||
std::string tmp_string = tmp_stream.str(); \ | ||
log_handler->Handle(level, __FILE__, __LINE__, tmp_string.c_str(), attributes); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably there is something I missed. What's is different behavior with this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also didn't get the point, could you please explain this change?
To my understanding, C++ specifications will ensure the temporary object should be freed only after this code block(Handle(...)
).
https://en.cppreference.com/w/cpp/language/lifetime#Temporary_object_lifetime
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're correct.
We've previously encountered a core dump caused by c_str(), similar to the situation described in https://stackoverflow.com/questions/27627413/why-does-calling-c-str-on-a-function-that-returns-a-string-not-work.
The code was as follows:
auto cstr = tmp_stream.str().c_str();
f(cstr);
This caused cstr
to become an invalid pointer passed into function f.
However, in this case, Handle(level, FILE, LINE, tmp_stream.str().c_str(), attributes) is within a single expression, so this issue doesn't exist.
When I saw this core dump, my habitual aversion to the c_str() function led to a misjudgment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in the example you shared and aslo the stackoverflow link, the temporary object returned from function reaches the end of its lifetime at the end of the including its expression, which means the temporary object is no longer valid after the ";", but the lifetime of local variable is different and will reach the end of current block, like @owent mentioend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the issue report and PR.
I do not agree with the root cause analysis, and as a result the code change proposed does not resolve or improve anything, in my understanding.
Details below.
"In this macro, tmp_stream.str().c_str() returns a pointer to a temporary string. This temporary string is the return value of tmp_stream.str(), which will be destructed at the end of the current statement."
Agreed.
"Therefore, it is unsafe to continue using this pointer after the statement ends."
Agreed.
"If the log_handler->Handle function needs to access this string after the current statement, this macro may cause issues."
Do not agree.
If the handle function needs to access the string later, it first must make a copy of it, during the call to Handle().
The root cause of the crash seen is most likely that a raw pointer is held instead.
As @lalitb pointed out, this could be documented better to set expectations, but is not a bug caused by a temporary variable.
The "current" statement is:
log_handler->Handle(level, __FILE__, __LINE__, tmp_stream.str().c_str(), attributes);
The temporary used by tmp_stream.str()
will be destroyed after the current statement ends, that is, it still exists during the call to Handler().
The code change modifies this slightly, but the problem still remains that accessing the message after the Handle() method returns is not expected.
The previous contributors mentioned the issue of asynchrony. I'll study it further and report back to everyone once I make progress. |
As metioned by @marcalff , you should copy the strings and move them if you want to handle this log asynchrony. Move the temporary |
Thank you all for your help. I tried not calling
The corresponding code is :
After macro expansion, it becomes
I found through gdb that the argument for So it had a core dump before entering This is puzzling to me. I believe that it is absolutely impossible for it to crash at this location. Therefore, there might be some hidden issues elsewhere. It seems like there might be a wild pointer issue in the service, causing memory corruption. But why would it always crash in this function? It seems too coincidental. I tried using the |
@ninghejun Thanks for the details. If Typically in these cases, I would start to audit compiling and link options, to make sure the build itself is sane. Next, I would add some sample code in the application that writes to a Let's continue this investigation and discussion in issue #2393, because this does not concern the PR at hand. As for the PR, we all agree now that the change is not needed, and does not fix the (yet to be determined) root cause of the crash seen in your application, so the PR needs to be closed. |
Fixes #2393
Changes
Fix core dump issue in OTEL_INTERNAL_LOG_DISPATCH macro