【问题标题】:How to enable SIGFPE signal on division by zero in IOS app?如何在 IOS 应用程序中启用 SIGFPE 信号除以零?
【发布时间】:2012-10-06 18:06:32
【问题描述】:

我在 Xcode 4.5(llvm 4.1 编译器)中为 ios 5/6 开发了一个应用程序,并使用信号和异常处理程序来记录错误。但是我发现除以零永远不会引发 SIGFPE 信号。在 linux 系统上,我可以使用 feenableexcept 来设置陷阱。但这在ios中没有定义。

为 fenv_t.__fpscr 设置适当的位不起作用,至少对于 iphone 4 和 3gs 而言。

【问题讨论】:

    标签: ios xcode exception-handling divide-by-zero


    【解决方案1】:

    feenableexcept 函数是一个不属于标准 C 或 POSIX 的 linux 函数。没有可移植的方式来启用SIGFPE

    实际上,您需要不同的代码来在 iOS 模拟器和 iOS 设备上启用 SIGFPE,因为模拟器运行 x86 而设备运行 ARM。

    我认为(但尚未测试)您可以启用SIGFPE,方法是使用fegetenv 函数获取fenv_t,打开或关闭fenv_t 中的一些位,然后将其传递给@ 987654330@ 功能。 fenv_t 的定义是特定于处理器的。看看fenv.h

    对于 ARM,fenv_t 包含一个名为 __fpscr 的字段。这是floating point status and control register。您可以切换的位在fenv.h 中枚举为__fpscr_trap_invalid__fpscr_trap_divbyzero 等。大概您想打开__fpscr_trap_divbyzero 位。

    对于 x86,fenv_t 包含两个感兴趣的字段:__control(x87 控制字)和__mxcsr(SSE 控制/状态寄存器)。

    您可以在__control 中切换的位由fenv.h 中定义的FE_INEXACTFE_UNDERFLOW 等常量定义。我认为您必须关闭这些位 off 才能为这些异常启用SIGFPECheck the processor manual, §8.1.5.

    您可以在__mxcsr 中切换的位由xmmintrin.h 中的_MM_MASK_INVALID__MM_MASK_DENORM 等常量定义。我认为您需要关闭这些位关闭 以启用SIGFPE。检查处理器手册,§10.2.3。

        fenv_t fe;
        if (fegetenv(&fe) != 0) {
            // error
        }
    
    #if defined __arm__
        fe.__fpscr |= __fpscr_trap_divbyzero;
    #elif defined __i386__
        fe.__control &= ~FE_DIVBYZERO;
        fe.__mxcsr &= ~_MM_MASK_DIV_ZERO;
    #else
    #error unknown processor architecture
    #endif
    
        if (fesetenv(&fe) != 0) {
            // error
        }
    

    您可能还需要为所有处理器执行#pragma STDC FENV_ACCESS ON

    同样,我还没有测试过这些。祝你好运。

    【讨论】:

    • 这不起作用,即使 fesetenv 设置的值没问题。顺便说一下,这个 i386 魔法也不起作用。
    • 这只会让 cpu 设置标志,不会引发异常。如果按照 Rob 的描述启用标志,则需要在每个运行循环或执行除法之后检查标志。像这样: int set_excepts = fetestexcept(FE_DIVBYZERO); if (set_excepts & FE_DIVBYZERO) { cerr
    • 这听起来像是一个正确的方法,并且适用于桌面和模拟器,但我无法使其适用于设备 - 既不适用于__arm__,也不适用于__arm64__。我已经逐条调试它,达到了fesetenv()执行FMXR指令将更新的值写入FPSCR,但寄存器的值没有改变的地步。
    • Apple 的 ARM 架构实现似乎不支持浮点捕获。根据 ARM Ltd 的参考手册,这是实现架构时允许的选项。
    【解决方案2】:

    您解决此问题的选择是:

    按照 Rob 所说的,使用一个函数启用浮点除以零陷阱,然后定期检查标志:

    #include "fenv.h"
    #include <iostream>
    #include <csignal>
    void CheckForDivideByZeroException()
    {
        int set_excepts;
        set_excepts = fetestexcept(FE_DIVBYZERO);
    
        if (set_excepts & FE_DIVBYZERO) {
            cerr<<"Divide by zero!!!"<<endl;
            feclearexcept(FE_DIVBYZERO);
        }
    }
    void EnableDivideByZeroExceptions()
    {
        fenv_t fe;
        if (fegetenv(&fe) != 0) {
            cerr<<"ERROR - Unable to get floating point status and control register"<<endl;
            raise(SIGINT);
        }
    
    #if defined __arm__
        fe.__fpscr |= __fpscr_trap_divbyzero;
    #elif defined __i386__
        fe.__control &= ~FE_DIVBYZERO;
        fe.__mxcsr &= ~_MM_MASK_DIV_ZERO;
    #else
    #error unknown processor architecture
    #endif
    
        if (fesetenv(&fe) != 0) {
            cout<<"ERROR - Unable to trap div by zero errors"<<endl;
            raise(SIGINT);
        }
    }
    #endif
    

    或者您的另一个选择是通过将以下内容添加到您的 OTHER_CFLAGS 构建设置中来启用 xcode 中的标志,该标志将引发具有所有未定义行为的异常

    -fcatch-undefined-behavior
    

    【讨论】:

      猜你喜欢
      • 2011-11-08
      • 2012-02-06
      • 2013-12-16
      • 1970-01-01
      • 1970-01-01
      • 2013-05-29
      • 1970-01-01
      • 2017-06-23
      • 2015-07-11
      相关资源
      最近更新 更多