在此问答中,确定您应该始终致电 va_end()
:
但是如果你到达va_end之前有一段代码longjmp呢? va_end的部分是否有任何承诺可以接受?或者在概念上可能是它 (例如) 做一个内存分配 va_start()
那会被泄露,而不仅仅是使用堆栈技巧?
在此问答中,确定您应该始终致电 va_end()
:
但是如果你到达va_end之前有一段代码longjmp呢? va_end的部分是否有任何承诺可以接受?或者在概念上可能是它 (例如) 做一个内存分配 va_start()
那会被泄露,而不仅仅是使用堆栈技巧?
该 C99理由 明确说明 va_start
可以分配最终释放的内存 va_end
,正是你在问题中猜到的:
7.15.1.2
va_copy
宏[...]
30一个更简单的方法是复制
va_list
用于表示参数处理的对象。但是,没有安全的方法 在C89中执行此操作,因为该对象可能包含指向由内存分配的内存的指针va_start
宏观和被摧毁va_end
宏。
新的va_copy
宏提供了这种安全机制。[...]
所以是的,你需要调用 va_end
在...之前 longjmp
。至少你会在这样的实现上发生内存泄漏。
据说金字塔OSx有一个实现内存分配的实现 va_start
。函数参数在寄存器中传递。即使对于可变函数也是如此。它可能早于ANSI C发明的函数原型,这意味着调用者不知道它是否处理可变函数。 va_start
分配内存,大概是以某种方式存储函数参数值 va_arg
可以轻松访问它。 va_end
释放分配的内存。
它的实施 va_start
和 va_end
实际上需要匹配 va_start
和 va_end
从语法上讲,因为它是一个使用不平衡的括号,所以ANSI C已经不允许这种实现,但是同样的原则可以在匹配大括号时工作。
我可以找到关于这个实现的非常少的具体信息,它在80年代末,90年代早期的Usenet上只是点点滴滴。我找到的一点点可能是不完整的,甚至是完全错误的。更多细节非常受欢迎,尤其是那些自己使用此实现的人。
如果你正在使用 jmp_buff
存储在全局变量(通常的模式)中,制作它的副本并使用它应该是安全的 setjmp
所以 longjmp
将转到您的代码而不是外部调用者;的情况下 longjmp
,然后你的代码可以调用 va_end
和 longjmp
使用存储的缓冲区副本;如果您的代码正常退出,则需要在返回之前恢复全局缓冲区。