☰
  • 首页
  • 规则分类
  • 项目介绍
search
•••

禁用 setjmp、longjmp

9.7.4 ID_forbidLongjmp
目录 › next › previous

setjmp、longjmp 可以在函数间跳转,进一步破坏了结构化编程理念,非框架代码不应使用。

setjmp 与 longjmp 由类型为 jmp_buf 的参数关联,只能在同一线程中使用,如果调用 longjmp 时没有对应的 setjmp,或 setjmp 所在函数已经结束执行,会导致标准未定义的行为,而且要注意 setjmp、longjmp 无法与 C++ 对象自动析构等机制兼容,极易造成意料之外的错误。

示例:

jmp_buf buf;

float div(int a, int b) {
    if (b == 0) {
        longjmp(buf, 1);     // Non-compliant
    }
    return (float)a / b;
}

int main() {
    if (setjmp(buf) == 0) {          // Non-compliant
        printf("%f\n", div(3, 0));
    } else {
        return 1;
    }
}

setjmp 返回 0 表示设置跳转位置成功,之后如果调用 longjmp 会跳回 setjmp 的位置,这时 setjmp 返回非 0 值,这种机制在 C 语言中可以用作异常处理,也可以实现“协程”等概念,但会严重地降低代码可读性,在普通的业务逻辑或算法实现中不应使用。

另外,函数间跳转与编译器的优化机制也会产生冲突,如:

jmp_buf buf;

void foo() { longjmp(buf, 1); }

void bar() {
    int i = 1;            // Missing ‘volatile’
    if (!setjmp(buf)) {
        i++;
        foo();
    } else {
        printf("%d\n", i);
    }
}

这段代码在启用优化时和关闭优化时可能会有不同的输出,启用优化时局部变量 i 可能直接存于寄存器,当通过 longjmp 跳转回 bar 函数时,i++ 的结果会丢失。将局部变量用 volatile 限定可解决这种问题,但很容易遗漏或产生无必要的限定。

依据

ISO/IEC 9899:1999 7.13.2.1(2)-undefined ISO/IEC 14882:2011 18.10(4)-undefined

参考

C++ Core Guidelines SL.C.1 MISRA C 2004 20.7 MISRA C 2012 21.4 MISRA C++ 2008 17-0-5 SEI CERT ERR52-CPP
Copyright©2024 360 Security Technology Inc., Licensed under the Apache-2.0 license.