Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Expose disjoint mapping unwinder bug with older Android devices
#!/bin/bash -e
# On an older device (Galaxy Nexus S running Android 4.1.2), an executable built
# with -z,max-page-size=0x10000 has a gap of size 0x1e000 between its R+E and
# R+W segments. If a DSO is loaded into the gap, then that DSO may hit a bug in
# old versions of Android where dl_unwind_find_exidx searches the executable
# rather than the DSO.
# This test program runs 10 times and typically fails a few times, depending on
# whether ASLR puts a DSO into the gap. Failure looks like so:
# terminating with uncaught exception of type int
# assertion "terminating with uncaught exception of type int" failed: file "/usr/local/google/buildbot/src/android/ndk-release-r21/external/libcxx/../../external/libcxxabi/src/abort_message.cpp", line 72, function "abort_message"
# Segmentation fault
# If both the executable *and* DSO are built with a 64KB max-page-size, then the
# DSO probably won't fit into the gap. Newer devices seem(?) to lay out memory
# differently, so that a DSO won't accidentally land in the gap.
# The Bionic bug was fixed in Android Q and up:
cat >main.cpp <<EOF
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/mman.h>
int somevar = 42;
void func1(); void func2(); void func3();
void func4(); void func5(); void func6();
int main() {
func1(); func2(); func3();
func4(); func5(); func6();
if (false) {
char cmd[256];
snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", (int)getpid());
return 0;
cat >mylib.cpp <<EOF
#include <stdio.h>
void FUNC() {
try {
throw 42;
} catch (int i) {
printf("%s: caught %d\n", __FUNCTION__, i);
$CXX mylib.cpp -fpic -shared -o -DFUNC=func1
$CXX mylib.cpp -fpic -shared -o -DFUNC=func2
$CXX mylib.cpp -fpic -shared -o -DFUNC=func3
$CXX mylib.cpp -fpic -shared -o -DFUNC=func4
$CXX mylib.cpp -fpic -shared -o -DFUNC=func5
$CXX mylib.cpp -fpic -shared -o -DFUNC=func6
$CXX main.cpp $MAX_PAGE_SIZE -o main \ \ \ \ \ \
adb shell rm -fr $REMOTE_DIR
adb shell mkdir -p $REMOTE_DIR
adb push \
main \ \ \ \ \ \ \
adb shell "for i in 1 2 3 4 5 6 7 8 9 10; do LD_LIBRARY_PATH=$REMOTE_DIR $REMOTE_DIR/main; done"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment