commit | d90291b46b808946ad99a94a2f2992431fbc8c83 | [log] [tgz] |
---|---|---|
author | Martin Stjernholm <mast@google.com> | Thu May 27 20:54:22 2021 +0100 |
committer | Martin Stjernholm <mast@google.com> | Thu Jun 03 09:10:14 2021 +0000 |
tree | a25817509f8489c795b1a33f64627760bf571ac0 | |
parent | 5c824937bb82adbde857bc99cb03c769c9f68f7b [diff] |
Fix bitrot in the libnativebridge tests. - Bitrot 1: NativeBridge2Signal_test stopped working when version 3 was added in https://r.android.com/234059. - Bitrot 2: The code path that PreInitializeNativeBridgeFail1_test tested was removed completely when missing app data directory was allowed in https://r.android.com/1208629, so delete the test. - Use cc_test_library for the dynamic test libs so they are installed in the test directory rather than in system/lib(64). - Use test_per_src since native_bridge.cc doesn't support reloading the native bridge implementation lib after unloading. - Add a custom script to run the tests and a preupload check that the script is run. (Configuring atest for these tests still TBD in b/189484095 - test_per_src is a complication.) Test: art/libnativebridge/tests/runtests.sh Bug: 122710865 Bug: 189484095 Change-Id: Ib2b387e1d858127ca4bb44c548a5105ea8b838d8
In the Android operating system all non-native system and application processes are forked from the Zygote. As such, one of the Zygote's responsibilities is to change the stack protector cookie when a new process is created in order to prevent all processes from sharing the same value. When the stack protector cookie is changed all existing stack frames that have protectors will fail their check. This means that the call path from ZygoteInit.main() to the fork site in zygote::ForkCommon() cannot contain any functions with stack protectors. This must be true not just for the main zygotes, but also for the AppZygotes and WebViewZygote.
To achieve this goal the relevant native Zygote functions in frameworks/base and several functions in the ART interpreter have bee marked with __attribute__((no_stack_protector))
. If you are debugging an issue with a SIGABRT message of "stack corruption detected" and you are sure it isn't a legitimate case of corruption it is possible that a function has been added somewhere along this critical path and contains a stack protector.
If the function in the stack immediately proceeding the call to __stack_chk_fail
corresponds to a recently added call site in a function already marked with NO_STACK_PROTECTOR
it is probably sufficient to add this annotation macro to the offending function. However, it is possible for a properly annotated function to still contain a stack protector. This can be caused when a function marked as alwaysinline
, but not no_stack_protector
, is called. Because the compiler views undefined and a negative condition as the same thing it can't tell the difference between "no annotation" and no_stack_protector
. Thus it will promote the stack protector status of the caller, causing this hard to detect behavior.
The first thing to check is to see if any uses of the raw __attribute__((alwaysinline))
have been added. If this has occurred, replace the raw attribute with the ALWAYS_INLINE
macro when possible or, if not, add the no_stack_protector
to the attribute list. If this doesn't solve the issue (this should be very rare), you will need to use the following steps to get a list of the inline events in the function that are caused by alwaysinline
.
alwaysinline
First, you will need to obtain a copy of the LLVM opt
binary built in debug mode. You can do this by downloading and building a version from source, using a copy from Google3, or asking a member of the LLVM team to provide one.
Next, successfully build a copy of android and then run the following command:
$> prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-${TARGET_PRODUCT}.ninja -t query path/to/file.cc
This will produce a list of object files generated by the build system from this source file. Select one of those object files and use it in this command:
$> prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-${TARGET_PRODUCT}.ninja -t commands path/to/object/file.o | tail -1
Now you can add the -save-temps
option to the command you got from the previous command and run it in your Android root directory. This will produce a series of <file_basename>.*
files. Next, run
$> llvm-dis <file_basename>.bc
to convert the .bc
file to a .ll
file. The next step is to run the .ll
file through opt
and get it to list the inline events triggered by alwaysinline
.
$> opt <file_basename>.ll -passes=inline -filter-print-funcs=<mangled function name> -S 2>&1 1>/dev/null -debug-only=inline -o /dev/null | grep always > <file_basename>_inlines.txt
This file contains a bunch of extraneous information which can be removed via this command:
$> cut -d @ -f 2 < <file_basename>_inlines.txt | cut -d \( -f 1 > <file_basename>_inlines_names_only.txt
Next you will need to open the <file_basename>.ll
file in a text editor and locate the beginning and ending line numbers for the function in question. Use those lines in the command below for the $1
and $2
values.
sed -n '$1,$2p' <file_basename>.ll > <function_name>.ll
Lastly, you can get the set of functions inlined into your target function via alwaysinline
using this command:
for i in `cat <file_basename>_inlines_names_only.txt`; do grep $i <function_name>.ll; done