bionic: fix broken end atrace events

When calling write on an FD for trace_marker, it is expected that the
pointer passed will be paged into memory. If this isn't the case, the
kernel will ignore the string passed and instead write "<faulted>" to
the ring buffer.

For end events, we were passing a constant string which resides in
the rodata section of the ELF file. If this section is paged out, we
end up not closing atrace stacks correctly leading to very broken traces.

For even more context, see the associated bug.

Fix this issue by reading the constant string to the stack first
which should mean the string is always paged in.

Bug: 197620214
Change-Id: I6a444ac6fe83a6a9fb696c5621e392eca7e9437a
This commit is contained in:
Lalit Maganti 2021-08-26 15:46:50 +01:00
parent 957d6d513e
commit 2aa3f7cb26
1 changed files with 15 additions and 1 deletions

View File

@ -86,7 +86,21 @@ void bionic_trace_end() {
return;
}
TEMP_FAILURE_RETRY(write(trace_marker_fd, "E|", 2));
// This code is intentionally "sub-optimal"; do not optimize this by inlining
// the E| string into the write.
//
// This is because if the const char* string passed to write(trace_marker) is not
// in resident memory (e.g. the page of the .rodata section that contains it has
// been paged out, or the anonymous page that contained a heap-based string is
// swapped in zram), the ftrace code will NOT page it in and instead report
// <faulted>.
//
// We "fix" this by putting the string on the stack, which is more unlikely
// to be paged out and pass the pointer to that instead.
//
// See b/197620214 for more context on this.
volatile char buf[2]{'E', '|'};
TEMP_FAILURE_RETRY(write(trace_marker_fd, const_cast<const char*>(buf), 2));
}
ScopedTrace::ScopedTrace(const char* message) : called_end_(false) {