setjmp and undefined behaviour

A

ais523

I've found what I think might be a compiler bug, but which might just be
me failing to understand things.

Here's the simplest example I've found to reproduce the bug:

== cut here ==
#include <setjmp.h>
#include <string.h>

int main(void)
{
char *volatile b = "test";
char *a = b;
jmp_buf j;
int i = 0;
while (1) {
/* a, b, and i are all determinate here, either from the
previous iteration of the while loop or from being
initialized at the start of the program

However, gcc produces a warning:

setjmp-issue.c:21:9: warning: variable ¡__s1¢ might be clobbered by ¡longjmp¢ or ¡vfork¢ [-Wclobbered]
if (strcmp(a, "test") == 0) {
^
*/
if (strcmp(a, "test") == 0) {
if (setjmp(j) == 0) {
/* setjmp returns twice; if it returns 0, it was due to
being called directly, thus a is stil determinate */
i = 1;
} else {
/* if setjmp returns 1, it was due to a longjmp; i is
indeterminate at this point (7.13.2.1p3), a is still
determinate because it hasn't changed since the longjmp */
i = 0;
a = "test";
/* now i is determinate again because I assigned an explicit
value to it */
}
}
/* a, b, and i are all determinate here; b never became
indeterminate because it's volatile, a and i are either
determinate from the if block, or have the same values as on
the previous iteration of the while loop */
if (b && i)
longjmp(j, 1);
}
return 0;
}
== cut here ==

A version without the comments, making it easier to see the control
flow:

== cut here ==
#include <setjmp.h>
#include <string.h>

int main(void)
{
char *volatile b = "test";
char *a = b;
jmp_buf j;
int i = 0;
while (1) {
if (strcmp(a, "test") == 0) {
if (setjmp(j) == 0) {
i = 1;
} else {
i = 0;
a = "test";
}
}
if (b && i)
longjmp(j, 1);
}
return 0;
}
== cut here ==

gcc 4.8.1 thinks that the strcmp() call here is undefined behaviour, but
as far as I can tell, `a` has a defined and determinate value no
matter how the control flow reaches that point: it's initialized to a
determinate value, and the only time that its value becomes
indeterminate (due to setjmp() returning), it's assigned a defined value
again before being used. I've also taken care to avoid undefined
behaviour elsewhere in the program.

Am I missing something here? Or is the compiler?
 
J

James Kuyper

I've found what I think might be a compiler bug, but which might just be
me failing to understand things.

Here's the simplest example I've found to reproduce the bug:

== cut here ==
#include <setjmp.h>
#include <string.h>

int main(void)
{
char *volatile b = "test";
char *a = b;
jmp_buf j;
int i = 0;
while (1) {
/* a, b, and i are all determinate here, either from the
previous iteration of the while loop or from being
initialized at the start of the program

However, gcc produces a warning:

setjmp-issue.c:21:9: warning: variable �__s1� might be clobbered by �longjmp� or �vfork� [-Wclobbered]
if (strcmp(a, "test") == 0) {
^
*/
if (strcmp(a, "test") == 0) {
if (setjmp(j) == 0) {
/* setjmp returns twice; if it returns 0, it was due to
being called directly, thus a is stil determinate */
i = 1;
} else {
/* if setjmp returns 1, it was due to a longjmp; i is
indeterminate at this point (7.13.2.1p3), a is still
determinate because it hasn't changed since the longjmp */
i = 0;
a = "test";
/* now i is determinate again because I assigned an explicit
value to it */
}
}
/* a, b, and i are all determinate here; b never became
indeterminate because it's volatile, a and i are either
determinate from the if block, or have the same values as on
the previous iteration of the while loop */
if (b && i)
longjmp(j, 1);
}
return 0;
}

"... values of objects of automatic storage duration that are local to
the function containing the invocation of the corresponding setjmp macro
that do not have volatile-qualified type and have been changed between
the setjmp invocation and longjmp call are indeterminate."

The variables a, i, and j all have automatic storage duration, are all
local to main(), which is the function containing the invocation of
setjmp(), and non of them have volatile-qualified type. Therefore, if
any of them are changed between the invocation of setjmp() and the call
to longjmp(), their value is indeterminate.

A careful analysis of your logic (if I've done that analysis correctly)
implies that this never actually causes a problem, despite the fact that
your code changes both the value of 'i' and 'a'. However, gcc is not
required to perform that analysis. It is well within it's rights to warn
you that this code is dangerous, without having performed the analysis
needed to determine that the danger never actually occurs. That's why
this is a warning, not a fatal error.
 
G

glen herrmannsfeldt

(snip)
setjmp-issue.c:21:9: warning: variable ???__s1??? might be clobbered
by ???longjmp??? or ???vfork??? [-Wclobbered]
(snip)

gcc 4.8.1 thinks that the strcmp() call here is undefined behaviour,
but as far as I can tell, `a` has a defined and determinate value no
matter how the control flow reaches that point: it's initialized to a
determinate value, and the only time that its value becomes
indeterminate (due to setjmp() returning), it's assigned a defined
value again before being used. I've also taken care to avoid undefined
behaviour elsewhere in the program.
Am I missing something here? Or is the compiler?

I don't know about this specific case, but for many warnings like the,
the compiler can't really be sure and so is issuing the warning.

Consider something more obvious like:

int i;
if(something) i=3;
if(something) printf("%d\n",i);

It wouldn't surprise me to see a compiler warn about the possibility
that i might not be defined for the printf.

No matter how good they make the compilers, people will always find
a case where the logic fails.

The rules regarding setjmp() and longjmp() are reasonably specific,
but I don't know them well enough to say.

-- glen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top