将setJMP和longJMP与本地JMP_BUF一起使用
如果本地jmp_buf
实际上由寄存器而不是堆栈内存表示,那么setJMP
或longjmp
有可能导致内容的内容setJmp
从longjmp
返回时,本地jmp_buf
是不确定的吗?
建议的重复是一个setJmp()调用多次允许多次执行longjmp()?在全局变量的上下文中问。有人建议,因为答案解释了该变量不会以阻止其随后被称为的方式进行修改,这也足够回答了局部变量的问题。
,但是 ,局部变量的处理与全局变量不同。特别是,如果本地jmp_buf
实际上保存在寄存器中,而不是内存中,则在longjmp
之后的恢复可能不会呈现可重复使用的jmp_buf
varible。
作为一项学术练习,我试图使用setJMP
作为goto
的替代品。为了使循环替换本地为函数,jmp_buf
使用的也是局部变量。
void foo (int n) {
jmp_buf jb;
volatile int i = 0;
setjmp(jb);
if (i < n) {
do_stuff(i);
longjmp(jb, ++i);
}
}
感谢 vinipsmaker 指出使用setjmp
具有某些限制,这使得有一定的限制将其返回值分配给变量不确定。
我知道,在setJmp
调用和longjmp
调用之间已修改的非挥发性本地变量在longjmp
。但是,我对本地jmp_buf
变量本身感到好奇,尤其是在jmp_buf
变量的情况下,寄存器代表寄存器而不是堆栈上的内存。
目前尚不清楚longjmp
本身是否可以被视为可以修改本地jmp_buf
变量的东西,以及当setjmp
返回时,这是否意味着其内容是未指定的。致电longjmp
之后。
我以为我可以通过声明jb
为volatile
来轻松派遣问题,但是这引起了警告(我将其视为错误):
... error: passing argument 1 of ‘_setjmp’ discards ‘volatile’ qualifier from pointer target type [-Werror=discarded-qualifiers]
setjmp(jb);
^~
另外,setJMP 不说它是否在设置
jmp_buf
之后还是在设置jmp_buf
之前保存寄存器值。
如果我需要关注它,我可以创建jmp_buf
的挥发性副本,然后复制其内容。但是,如果不需要,我想避免这种情况。
In the case that a local jmp_buf
is actually represented by registers rather than stack memory, is it possible for setjmp
or longjmp
to cause the contents of the local jmp_buf
to be indeterminate when setjmp
returns from a longjmp
?
The suggested duplicate Is it allowed to do longjmp() multiple times for one setjmp() call? asks in the context of a global variable. It was suggested since the answer explains that the variable is not modified in a way that would prevent it from being subsequently called, that sufficiently answers the question for a local variable too.
However, treatment of a local variable differs from a global variable. In particular, if the local jmp_buf
variable is actually held in registers and not memory, restoration after longjmp
may not render a reusable jmp_buf
variable.
As an academic exercise, I was attempting to use setjmp
as a substitute for goto
. To keep the loop replacement local to the function, the jmp_buf
used is also a local variable.
void foo (int n) {
jmp_buf jb;
volatile int i = 0;
setjmp(jb);
if (i < n) {
do_stuff(i);
longjmp(jb, ++i);
}
}
Thanks to vinipsmaker for pointing out that use of setjmp
has certain restrictions, which make assigning its return value to a variable undefined.
I understand that non-volatile local variables that have been modified between the setjmp
call and the longjmp
call are unspecified after longjmp
. However, I was curious about the local jmp_buf
variable itself, particularly in the case where the jmp_buf
variable is represented by registers rather than memory on the stack.
It is unclear if longjmp
itself can be considered something that may modify the local jmp_buf
variable, and whether this means its contents are unspecified when setjmp
returns after the call to longjmp
.
I thought I could easily dispatch the issue by declaring jb
to be volatile
, but this triggered a warning (which I treat as an error):
... error: passing argument 1 of ‘_setjmp’ discards ‘volatile’ qualifier from pointer target type [-Werror=discarded-qualifiers]
setjmp(jb);
^~
Also, the specification of setjmp
does not speak to whether it is saving the register values as they would be after setting the jmp_buf
or before setting the jmp_buf
.
If I need to be concerned about it, I can create a volatile copy of the jmp_buf
and copy its contents around. But, I'd like to avoid that if it isn't required.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
c11标准节第3点状态:
您的
JMP_BUF
对象未更改setJMP(JB)
和longjmp(jb,++ i)
。呼叫之间更改的唯一变量是i
,如标准所建议的那样,该变量被声明为volatile
。因此,要回答您的问题,
longjmp
本身不能“修改本地jmp_buf
[以这样的方式],当setJmp 返回”,但通过其他方式在两个调用之间修改
JMP_BUF
肯定会导致麻烦。The C11 standard section §7.13.2.1 point 3 states:
Your
jmp_buf
object is not changed betweensetjmp(jb)
andlongjmp(jb, ++i)
. The only variable which is changed between the calls isi
, which is declaredvolatile
, as the standard suggests.So, to answer your question,
longjmp
cannot by itself "modify the contents of the localjmp_buf
[in such a way] that would cause its contents to be undefined whensetjmp
returns", but modifying thejmp_buf
between the two calls through other means could definitely cause trouble.经过几天的研究,我同意@jxh的答案(标准还不够清楚)。但是,我应该在这里添加几件事。首先,您的程序不能保证出于另一个原因而工作。根据ISO/IEC 9899:2011§7.13.1.1.4¶4:
IOW,您可能不会将
setJmp()
的结果分配给变量。将此事暂时搁置一会儿,我开始怀疑我们 是否可以进行更改,以便您的代码变得合法(假设提出的最弱的保证是
jmp_buf
首先<之后变得无效代码> longjmp())。我想到了以下内容:After several days researching the topic, I agree with @jxh's answer (standard isn't clear enough). However, there are a couple of things I should add here. First, your program is not guaranteed to work for another reason already. According to ISO/IEC 9899:2011 §7.13.1.1 ¶4:
IOW, you may not assign the result of
setjmp()
to a variable.Leaving this matter aside for a moment, I started to wonder whether we could make changes so your code becomes legal (assuming the weakest guarantee posed which is
jmp_buf
becoming invalid after firstlongjmp()
on it). I came up with the following:没关系。
相关说明,您不需要
volatile
在i
上,因为它是由setjmp()
分配给的。在非常仔细阅读
longjmp()
和我的k&amp; rc副本的人页面上,jb
的内容仅在您的功能正文中无效,意思是如果有第二个调用longjmp()
,它将看到jb
的有效视图。在可共同的假设中,有效代码不会在较新的标准版本中变得无效,因此今天仍然适用。tl; dr您无需标记类型
JMP_BUF
volatile的变量。That's fine.
On a related note, you don't need
volatile
oni
because it's assigned to bysetjmp()
.On a very careful reading of the man page for
longjmp()
and my copy of K&R C, the contents ofjb
are only invalid within the body of your function, meaning if there were a second call tolongjmp()
, it would see a valid view ofjb
. Under the resaonable assumption that valid code does not become invalid in newer standard versions, this will still apply today.TL;DR you don't need to mark variables of type
jmp_buf
volatile.tl; dr 由于标准尚不清楚,最好将本地
jmp_buf
视为不确定的值之后本地longjmp
。ISO/IEC 9899:2018§17.13.1.1.1¶2描述了
setJMP
的行为,并且描述了返回时发生的情况。我们推断出从
setJMP
成功返回的导致初始化jmp_buf
参数。但是,没有提及初始化是否考虑了具有自动存储持续时间的jmp_buf
本身(因此,本身可以用寄存器而不是内存表示)。ISO/IEC 9899:2018§7.13.2.1¶3描述了
longjmp
的行为,措辞与 marko :但是,之间单词的含义在某种程度上难以捉摸。该标准可以明确指定 之间的上下文在
setJmp
完成之后。例如,措辞可能已经说过:当前的措辞表明,应该将调用
setJmp
本身作为可能触发不确定条件的东西。但是,
longjmp
返回的语义可能涵盖了此问题。 ISO/IEC 9899:2018§17.13.2.1¶4州:可以将此句子解释为意味着
setJMP
的调用语义是从直接调用返回还是从longjmp
函数返回的情况。也就是说,setJMP
的返回表示JMP_BUF
参数是初始化的,可以由另一个longjmp
使用。但是,这尚不清楚。在最有限的解释中,就像子句仅说明setJMP
返回的值,而不是调用本身。由于语义是模棱两可的,因此可以将
JMP_BUF
对象值视为不确定时从longjmp
返回时。TL;DR Since the standard isn't clear, it is better to treat the value of a local
jmp_buf
as indeterminate after a locallongjmp
.ISO/IEC 9899:2018 §17.13.1.1 ¶2 describes the behavior of
setjmp
, and ¶3 describes what happens on return.We infer that a successful return from
setjmp
results in an initializedjmp_buf
argument. However, there is no mention if the initialization takes into account of thejmp_buf
itself having automatic storage duration (and so, itself could be represented by registers rather than by memory).ISO/IEC 9899:2018 §7.13.2.1 ¶3 describes the behavior of
longjmp
, and is worded the same as the 2011 text cited by Marko:However, the meaning of the word between is somewhat elusive. The standard could have explicitly specified the context of between to mean after
setjmp
completed. For example, the wording could have stated:The current wording suggests that one should include the invocation of
setjmp
itself as something that may trigger the indeterminate condition.There is a possibility that the semantics of the return of
longjmp
covers for this problem, however. ISO/IEC 9899:2018 §17.13.2.1 ¶4 states:This sentence could be interpreted to mean that the invocation semantics of
setjmp
is the same whether it returns from direct invocation or returns from alongjmp
function. That is, the return ofsetjmp
means thejmp_buf
argument is initialized and can be used by anotherlongjmp
. But again, this is not clear. In the most limiting interpretation, the as if clause only speaks to the value returned bysetjmp
, and not the invocation itself.Since the semantics are ambiguous, it is proper to treat the
jmp_buf
object value as indeterminate upon return fromlongjmp
.