我们遇到了一个奇怪的设备,名为Motorla RAZR i,带有x86 CPU和Android 4.1.2版(大约2013年)。
此设备有时会在本机代码中的GL操作中崩溃。我们最终将这个错误减少到几行无辜的函数调用:
void stackCorrupt() {
const EGLint configAttrs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE};
const EGLint contextAttrs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
const EGLint const surfaceAttrs[] = {EGL_WIDTH, 16, EGL_HEIGHT, 16, EGL_NONE};
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
EGLint numConfigs;
EGLConfig config;
eglChooseConfig(display, configAttrs, &config, 1, &numConfigs);
EGLContext context = eglCreateContext(display, config, NULL, contextAttrs);
EGLSurface surface = eglCreatePbufferSurface(display, config, surfaceAttrs);
// commenting out this call makes the stack clean again
eglMakeCurrent(display, surface, surface, context);
// only to know that the context is good
__android_log_print(ANDROID_LOG_DEBUG, "native-lib", "GL_RENDERER %s", glGetString(GL_RENDERER));
// Cleanup
eglDestroySurface(display, surface);
eglDestroyContext(display, context);
eglTerminate(display);
}
使用-fstack-protector-strong
编译时(如果我理解正确,这是默认的),在特定设备上调用此函数总是会导致
F /system/bin/app_process: stack corruption detected: aborted
但是如果我使用-fno-stack-protector
,执行就会继续,好像什么都没发生一样。这可能(如果我理解正确的情况)成为任何进一步执行的陷阱。更危险(因为不明确),将 -flto 添加到CFLAGS可以防止崩溃。
在上面的代码中,为了简洁,我删除了错误检查。实际上,所有通话都成功了。此外,清理部分不会更改 eglMakeCurrent()的堆栈抖动行为。
我很高兴创建一些沙箱来安全地执行此类代码,而不会危及我的应用程序的其余部分。
PS
我在Android上遇到了另一个奇怪的堆栈损坏案例, "stack corruption detected" when using glGetProgramiv ,但似乎没有提出任何解决办法。
在测试用例中,但在真实世界的应用中却没有,egl上下文的release会有所帮助:我在清理之前调用eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)
。
反汇编显示 -flto 会关闭堆栈保护程序。这不应该是一个很大的失望:如果我们的目标是优化通话,那么浪费时间检查是愚蠢的吗?
答案 0 :(得分:3)
TL; NR:这是误报。设备上的EGL库(自2013年以来从未更新过)不遵守多年后推出的TLS约定,而新的NDK(我们使用稳定的r13)错误地将我们无辜的功能归咎于堆栈粉碎。
我在Nov 2015的gcc maillist中发现了一条消息,指的是Apr 2013的修正:
x86 android:更改-fstack-protector guard默认为TLS
正在编译的人 4.2之前的原生代码Android很可能会使用旧版本 无论如何都是Android NDK的版本。
我想建议删除Bionic异常,例如:改变 要读的代码:
/* Handle stack protector */ if (!opts_set->x_ix86_stack_protector_guard) opts->x_ix86_stack_protector_guard = SSP_TLS;
假设是错误的,我们的代码在4.0到7.0的所有平台上都运行相同的jar,我们不想在某些目标设备上使用旧版本的NDK。实际上,NDK r14仍然支持android-9(a.k.a。2.3 GINGERBREAD)。
不幸的是,这意味着至少在这个设备上我们必须使用 -fno-stack-protector 运行我们的C ++代码的调试版本。幸运的是,发布版本( APP_OPTIM =发布)使用LTO,因此禁用了堆栈保护。