在调用va_end之前,longjmp可以吗?

时间:2015-08-27 21:13:59

标签: c language-lawyer c89 longjmp variadic-functions

在此Q& A中,确定您应始终致电va_end()

What exactly is va_end for? Is it always necessary to call it?

但是,如果在到达va_end之前有一段代码是longjmp? va_end的部分是否有任何承诺可以接受?或者概念上它可能(例如)va_start()中进行内存分配会泄露,而不仅仅是使用堆栈技巧?

1 个答案:

答案 0 :(得分:8)

C99 rationale明确指出va_start可能会分配最终由va_end释放的内存,这正是您在问题中所猜测的内容:

  

7.15.1.2 va_copy

     

[...]

     

30一种更简单的方法是复制用于表示参数处理的va_list对象。但是,没有安全的方法   在C89中执行此操作,因为该对象可能包含指向由va_start宏分配并由va_end宏销毁的内存的指针。
  新的va_copy宏提供了这种安全机制。

     

[...]

所以是的,您需要在va_end之前调用longjmp。至少你会在这种实现上发生内存泄漏。

据说Pyramid OSx有一个实现,其中内存分配由va_start执行。函数参数在寄存器中传递。即使对于可变函数也是如此。它可能早于ANSI C发明的函数原型,这意味着调用者不知道它是否处理可变函数。 va_start分配了内存,可能是以va_arg可以轻松访问它的方式存储函数参数值。 va_end释放了已分配的内存。

va_startva_end的实现实际上需要在语法上匹配va_startva_end,因为它是使用不平衡大括号的,因此ANSI C已经禁止该实现,但是同样的原则可以在匹配括号的同时工作。

我可以找到关于这个实现的非常少的具体信息,它在80年代末,90年代早期的Usenet上只是点点滴滴。我找到的一点点可能是不完整的,甚至是完全错误的。更多细节非常受欢迎,尤其是那些自己使用此实现的人。