1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
/* { dg-options "-fcondition-coverage -ftest-coverage" } */
/* { dg-do run { target native } } */
#include <setjmp.h>
jmp_buf buf;
void noop () {}
int identity (int x) { return x; }
/* This function is a test to verify that the expression isolation does not
break on a CFG with the right set of complex edges. The (_ && setjmp)
created complex edges after the function calls and a circular pair of
complex edges around the setjmp call. This triggered a bug when the search
for right operands only would consider nodes dominated by the left-most
term, as this would only be the case if the complex edges were removed. (_
&& setjmp) is undefined behavior, but it does happen in the wild.
__builtin_setjmp did not trigger this, so we need setjmp from libc. */
void
setjmp001 (int a, int b, int c)
{
if (a) /* conditions(1/2) true(0) */
/* conditions(end) */
noop ();
if (b) /* conditions(1/2) false(0) */
/* conditions(end) */
noop ();
if (c && setjmp (buf)) /* conditions(1/4) true(0 1) false(1) */
/* conditions(end) */
noop ();
}
/* Adapted from freetype-2.13.0 gxvalid/gxvmod.c classic_kern_validate */
int
setjmp002 (int a)
{
int error = identity(a);
if (error) /* conditions(1/2) true(0) */
/* conditions(end) */
goto Exit;
if (a+1) /* conditions(1/2) false(0) */
/* conditions(end) */
{
noop ();
if (setjmp (buf)) /* conditions(1/2) true(0) */
/* conditions(end) */
noop ();
if (error) /* conditions(1/2) true(0) */
/* conditions(end) */
noop ();
}
error--;
Exit:
return error;
}
int
setjmp003 (int a)
{
/* || setjmp is undefined behavior, so the result here does not have to
make sense. It would be nice if the result is not something like 35/4
conditions covered. */
if (a || setjmp (buf)) /* conditions(suppress) */
/* conditions(end) */
a += 12;
return a;
}
jmp_buf dest;
int
setdest ()
{
if (setjmp (dest)) /* conditions(2/2) */
return 1;
return 2;
}
void
jump ()
{
/* Protect the longjmp so it will only be done once. The whole purpose of
this function is to help test conditions and instrumentation around
setjmp and its complex edges, as both branches should count towards
coverage, even when one is taken through longjmp. If the jump is not
guarded it can cause an infinite loop as setdest returns to a point in
main before jump (), leading to an infinite loop. See PR
gcov-profile/114720. */
static int called_once = 0;
if (!called_once) /* conditions(suppress) */
{
called_once = 1;
longjmp (dest, 1);
}
}
int
main ()
{
setjmp001 (0, 1, 0);
setjmp002 (0);
setjmp003 (0);
setdest ();
jump ();
}
/* { dg-final { run-gcov conditions { --conditions gcov-22.c } } } */
|