【问题标题】:stack protection triggered by eglMakeCurrenteglMakeCurrent 触发的堆栈保护
【发布时间】:2017-06-30 15:01:52
【问题描述】:

我们遇到了一款名为 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 会隐藏崩溃。

在上面的代码中,为了简洁起见,我删除了错误检查。实际上,所有调用都会成功。此外,Cleanup 部分不会更改 eglMakeCurrent() 的堆栈抖动行为。

我真的很高兴创建一些沙盒来安全地执行此类代码,而不会危及我的应用程序的其余部分。

PS

  1. 我在 Android 上遇到了另一个奇怪的堆栈损坏案例,"stack corruption detected" when using glGetProgramiv,但似乎没有提出解决方案。

  2. 在测试用例中,而不是在实际应用中,egl 上下文的 release 会有所帮助:我在 Cleanup 之前调用 eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)

    李>
  3. 反汇编显示 -flto 关闭堆栈保护器。这应该不会让人大失所望:如果我们的目标是优化调用,那么浪费时间检查是愚蠢的吗?

【问题讨论】:

    标签: gcc opengl-es android-ndk opengl-es-2.0 lto


    【解决方案1】:

    TL;NR:这是误报。设备上的 EGL 库(自 2013 年以来从未更新)不遵守多年后引入的 TLS 约定,并且新的 NDK(我们使用稳定的 r13)错误地指责我们的无辜函数破坏堆栈。

    我在Nov 2015 的 gcc 邮件列表中发现一条消息,指的是 Apr 2013 的修复:

    x86 android:将 -fstack-protector 保护默认更改为 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=release) 使用 LTO,因此堆栈保护器被禁用。

    【讨论】:

      猜你喜欢
      • 2011-07-30
      • 2017-08-28
      • 2020-08-17
      • 2019-04-19
      • 2016-02-12
      • 2016-06-30
      • 2023-04-07
      • 2014-04-16
      • 2014-06-30
      相关资源
      最近更新 更多