Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Harden the detection of broken makecontext: check that makecontext arguments can...
[simgrid.git] / acmacro / context.m4
1 dnl AC_CHECK_UCONTEXT: Check whether ucontext are working
2
3 dnl Most of the code is stolen from the GNU pth autoconf macros by
4 dnl Ralf S. Engelschall. 
5 dnl # ``"Reuse an expert's code" is the right
6 dnl #   advice for most people. But it's a useless
7 dnl #   advice for the experts writing the code
8 dnl #   in the first place.'
9 dnl #               -- Dan J. Bernstein
10 dnl
11 dnl OK, you're definitely the expert on this point... :)
12
13 dnl ##
14 dnl ##  Display Configuration Headers
15 dnl ##
16 dnl ##  configure.ac:
17 dnl ##    AC_MSG_PART(<text>)
18 dnl ##
19
20 m4_define(AC_MSG_PART,[dnl
21 if test ".$enable_subdir" != .yes; then
22     AC_MSG_RESULT()
23     AC_MSG_RESULT(${TB}$1:${TN})
24 fi
25 ])dnl
26
27 dnl ##
28 dnl ##  Display a message under --verbose
29 dnl ##
30 dnl ##  configure.ac:
31 dnl ##    AC_MSG_VERBOSE(<text>)
32 dnl ##
33
34 m4_define(AC_MSG_VERBOSE,[dnl
35 if test ".$verbose" = .yes; then
36     AC_MSG_RESULT([  $1])
37 fi
38 ])
39
40 dnl ##
41 dnl ##  Do not display message for a command
42 dnl ##
43 dnl ##  configure.ac:
44 dnl ##    AC_MSG_SILENT(...)
45 dnl ##
46
47 m4_define(AC_FD_TMP, 9)
48 m4_define(AC_MSG_SILENT,[dnl
49 exec AC_FD_TMP>&AC_FD_MSG AC_FD_MSG>/dev/null
50 $1
51 exec AC_FD_MSG>&AC_FD_TMP AC_FD_TMP>&-
52 ])
53
54 dnl ##
55 dnl ##  Check for direction of stack growth
56 dnl ##
57 dnl ##  configure.ac:
58 dnl ##    AC_CHECK_STACKGROWTH(<define>)
59 dnl ##  acconfig.h:
60 dnl ##    #undef <define>
61 dnl ##  source.c:
62 dnl ##    #include "config.h"
63 dnl ##    #if <define> < 0
64 dnl ##        ...stack grow down...
65 dnl ##    #else
66 dnl ##        ...stack grow up...
67 dnl ##    #endif
68 dnl ##
69
70 AC_DEFUN([AC_CHECK_STACKGROWTH],[dnl
71 AC_MSG_CHECKING(for direction of stack growth)
72 AC_CACHE_VAL(ac_cv_check_stackgrowth, [
73 cross_compiling=no
74 AC_TRY_RUN(
75 changequote(<<, >>)dnl
76 <<
77 #include <stdio.h>
78 #include <stdlib.h>
79 static int iterate = 10;
80 static int growsdown(int *x)
81 {
82     auto int y;
83     y = (x > &y);
84     if (--iterate > 0)
85         y = growsdown(&y);
86     if (y != (x > &y))
87         exit(1);
88     return y;
89 }
90 int main(int argc, char *argv[])
91 {
92     FILE *f;
93     auto int x;
94     if ((f = fopen("conftestval", "w")) == NULL)
95         exit(1);
96     fprintf(f, "%s\n", growsdown(&x) ? "down" : "up");;
97     fclose(f);
98     exit(0);
99 }
100 >>
101 changequote([, ])dnl
102 ,
103 ac_cv_check_stackgrowth=`cat conftestval`,
104 ac_cv_check_stackgrowth=down,
105 ac_cv_check_stackgrowth=down
106 )dnl
107 ])dnl
108 AC_MSG_RESULT([$ac_cv_check_stackgrowth])
109 if test ".$ac_cv_check_stackgrowth" = ".down"; then
110     val="-1"
111 else
112     val="+1"
113 fi
114 AC_DEFINE_UNQUOTED($1, $val, [define for stack growth])
115 ])
116
117 dnl ##
118 dnl ##  Check whether SVR4/SUSv2 makecontext(2), swapcontext(2) and
119 dnl ##  friends can be used for user-space context switching
120 dnl ##
121 dnl ##  configure.ac:
122 dnl ##     AC_CHECK_MCSC(<success-action>, <failure-action>)
123 dnl ##
124
125 AC_DEFUN([AC_CHECK_MCSC], [
126 AC_MSG_CHECKING(for usable SVR4/SUSv2 makecontext(2)/swapcontext(2))
127 AC_CACHE_VAL(ac_cv_check_mcsc, [
128 AC_TRY_RUN([
129
130 #include <stdio.h>
131 #include <stdlib.h>
132 #include <ucontext.h>
133
134 ucontext_t uc_child;
135 ucontext_t uc_main;
136
137 void child(void *arg)
138 {
139     if (arg != (void *)2147483648)
140         exit(1);
141     if (swapcontext(&uc_child, &uc_main) != 0)
142         exit(2);
143 }
144
145 int main(int argc, char *argv[])
146 {
147     FILE *fp;
148     void *stack;
149
150     /* the default is that it fails */
151     if ((fp = fopen("conftestval", "w")) == NULL)
152         exit(3);
153     fprintf(fp, "no\n");
154     fclose(fp);
155
156     /* configure a child user-space context */
157     if ((stack = malloc(64*1024)) == NULL)
158         exit(4);
159     if (getcontext(&uc_child) != 0)
160         exit(5);
161     uc_child.uc_link = NULL;
162     uc_child.uc_stack.ss_sp = (char *)stack+(32*1024);
163     uc_child.uc_stack.ss_size = 32*1024;
164     uc_child.uc_stack.ss_flags = 0;
165     makecontext(&uc_child, child, 2, (void *)2147483648);
166
167     /* switch into the user context */
168     if (swapcontext(&uc_main, &uc_child) != 0)
169         exit(6);
170
171     /* Fine, child came home */
172     if ((fp = fopen("conftestval", "w")) == NULL)
173         exit(7);
174     fprintf(fp, "yes\n");
175     fclose(fp);
176
177     /* die successfully */
178     exit(0);
179 }
180 ],
181 ac_cv_check_mcsc=`cat conftestval`,
182 ac_cv_check_mcsc=no,
183 ac_cv_check_mcsc=no
184 )dnl
185 ])dnl
186 AC_MSG_RESULT([$ac_cv_check_mcsc])
187 if test ".$ac_cv_check_mcsc" = .yes; then
188     ifelse([$1], , :, [$1])
189 else
190     ifelse([$2], , :, [$2])
191 fi
192 ])dnl
193
194 dnl ##
195 dnl ##  Check how stacks have to be setup for the functions
196 dnl ##  sigstack(2), sigaltstack(2) and makecontext(2).
197 dnl ##
198 dnl ##  configure.ac:
199 dnl ##    AC_CHECK_STACKSETUP(sigstack|sigaltstack|makecontext, <macro-addr>, <macro-size>)
200 dnl ##  acconfig.h:
201 dnl ##    #undef HAVE_{SIGSTACK|SIGALTSTACK|MAKECONTEXT}
202 dnl ##    #undef HAVE_STACK_T
203 dnl ##  header.h.in:
204 dnl ##    @<macro-addr>@
205 dnl ##    @<macro-size>@
206 dnl ##  source.c:
207 dnl ##    #include "header.h"
208 dnl ##    xxx.sp_ss   = <macro-addr>(skaddr, sksize);
209 dnl ##    xxx.sp_size = <macro-size>(skaddr, sksize);
210 dnl ##
211
212 AC_DEFUN([AC_CHECK_STACKSETUP],[dnl
213 dnl #   check for consistent usage
214 ifelse($1,[sigstack],,[
215 ifelse($1,[sigaltstack],,[
216 ifelse($1,[makecontext],,[
217 errprint(__file__:__line__: [AC_CHECK_STACKSETUP: only sigstack, sigaltstack and makecontext supported
218 ])])])])
219 dnl #   we require the C compiler and the standard headers
220 AC_REQUIRE([AC_HEADER_STDC])dnl
221 dnl #   we at least require the function to check
222 AC_CHECK_FUNCS($1)
223 dnl #   sigaltstack on some platforms uses stack_t instead of struct sigaltstack
224 ifelse($1, sigaltstack, [
225     AC_ONCE(stacksetup_stack_t, [
226         AC_CHECK_TYPEDEF(stack_t, signal.h)
227     ])
228 ])
229 dnl #   display processing header
230 AC_MSG_CHECKING(for stack setup via $1)
231 dnl #   but cache the whole results
232 AC_CACHE_VAL(ac_cv_stacksetup_$1,[
233 if test ".$ac_cv_func_$1" = .no; then
234     dnl #   no need to check anything when function is already missing
235     ac_cv_stacksetup_$1="N.A.:/*N.A.*/,/*N.A.*/"
236 else
237     dnl #   setup compile environment
238     OCFLAGS="$CFLAGS"
239     CFLAGS="$CFLAGS -DTEST_$1"
240     cross_compiling=no
241     dnl #   compile and run the test program
242     AC_TRY_RUN([
243 #include <stdio.h>
244 #include <stdlib.h>
245 #include <string.h>
246 #if defined(TEST_sigstack) || defined(TEST_sigaltstack)
247 #include <sys/types.h>
248 #include <signal.h>
249 #include <unistd.h>
250 #endif
251 #if defined(TEST_makecontext)
252 #include <ucontext.h>
253 #endif
254 union alltypes {
255     long   l;
256     double d;
257     void  *vp;
258     void (*fp)(void);
259     char  *cp;
260 };
261 static volatile char *handler_addr = (char *)0xDEAD;
262 #if defined(TEST_sigstack) || defined(TEST_sigaltstack)
263 static volatile int handler_done = 0;
264 void handler(int sig)
265 {
266     char garbage[1024];
267     int i;
268     auto int dummy;
269     for (i = 0; i < 1024; i++)
270         garbage[i] = 'X';
271     handler_addr = (char *)&dummy;
272     handler_done = 1;
273     return;
274 }
275 #endif
276 #if defined(TEST_makecontext)
277 static ucontext_t uc_handler;
278 static ucontext_t uc_main;
279 void handler(void)
280 {
281     char garbage[1024];
282     int i;
283     auto int dummy;
284     for (i = 0; i < 1024; i++)
285         garbage[i] = 'X';
286     handler_addr = (char *)&dummy;
287     swapcontext(&uc_handler, &uc_main);
288     return;
289 }
290 #endif
291 int main(int argc, char *argv[])
292 {
293     FILE *f;
294     char *skaddr;
295     char *skbuf;
296     int sksize;
297     char result[1024];
298     int i;
299     sksize = 32768;
300     skbuf = (char *)malloc(sksize*2+2*sizeof(union alltypes));
301     if (skbuf == NULL)
302         exit(1);
303     for (i = 0; i < sksize*2+2*sizeof(union alltypes); i++)
304         skbuf[i] = 'A';
305     skaddr = skbuf+sizeof(union alltypes);
306 #if defined(TEST_sigstack) || defined(TEST_sigaltstack)
307     {
308         struct sigaction sa;
309 #if defined(TEST_sigstack)
310         struct sigstack ss;
311 #elif defined(TEST_sigaltstack) && defined(HAVE_STACK_T)
312         stack_t ss;
313 #else
314         struct sigaltstack ss;
315 #endif
316 #if defined(TEST_sigstack)
317         ss.ss_sp      = (void *)(skaddr + sksize);
318         ss.ss_onstack = 0;
319         if (sigstack(&ss, NULL) < 0)
320             exit(1);
321 #elif defined(TEST_sigaltstack)
322         ss.ss_sp    = (void *)(skaddr + sksize);
323         ss.ss_size  = sksize;
324         ss.ss_flags = 0;
325         if (sigaltstack(&ss, NULL) < 0)
326             exit(1);
327 #endif
328         memset((void *)&sa, 0, sizeof(struct sigaction));
329         sa.sa_handler = handler;
330         sa.sa_flags = SA_ONSTACK;
331         sigemptyset(&sa.sa_mask);
332         sigaction(SIGUSR1, &sa, NULL);
333         kill(getpid(), SIGUSR1);
334         while (!handler_done)
335             /*nop*/;
336     }
337 #endif
338 #if defined(TEST_makecontext)
339     {
340         if (getcontext(&uc_handler) != 0)
341             exit(1);
342         uc_handler.uc_link = NULL;
343         uc_handler.uc_stack.ss_sp    = (void *)(skaddr + sksize);
344         uc_handler.uc_stack.ss_size  = sksize;
345         uc_handler.uc_stack.ss_flags = 0;
346         makecontext(&uc_handler, handler, 1);
347         swapcontext(&uc_main, &uc_handler);
348     }
349 #endif
350     if (handler_addr == (char *)0xDEAD)
351         exit(1);
352     if (handler_addr < skaddr+sksize) {
353         /* stack was placed into lower area */
354         if (*(skaddr+sksize) != 'A')
355              sprintf(result, "(skaddr)+(sksize)-%d,(sksize)-%d",
356                      sizeof(union alltypes), sizeof(union alltypes));
357         else
358              strcpy(result, "(skaddr)+(sksize),(sksize)");
359     }
360     else {
361         /* stack was placed into higher area */
362         if (*(skaddr+sksize*2) != 'A')
363             sprintf(result, "(skaddr),(sksize)-%d", sizeof(union alltypes));
364         else
365             strcpy(result, "(skaddr),(sksize)");
366     }
367     if ((f = fopen("conftestval", "w")) == NULL)
368         exit(1);
369     fprintf(f, "%s\n", result);
370     fclose(f);
371     exit(0);
372 }
373 ],[
374 dnl #   test successully passed
375 ac_cv_stacksetup_$1=`cat conftestval`
376 ac_cv_stacksetup_$1="ok:$ac_cv_stacksetup_$1"
377 ],[
378 dnl #   test failed
379 ac_cv_stacksetup_$1='guessed:(skaddr),(sksize)'
380 ],[
381 dnl #   cross-platform => failed
382 ac_cv_stacksetup_$1='guessed:(skaddr),(sksize)'
383 ])
384 dnl #   restore original compile environment
385 CFLAGS="$OCFLAGS"
386 ])dnl
387 fi
388 dnl #   extract result ingredients of single cached result value
389 type=`echo $ac_cv_stacksetup_$1 | sed -e 's;:.*$;;'`
390 addr=`echo $ac_cv_stacksetup_$1 | sed -e 's;^.*:;;' -e 's;,.*$;;'`
391 size=`echo $ac_cv_stacksetup_$1 | sed -e 's;^.*:;;' -e 's;^.*,;;'`
392 dnl #   export result ingredients
393 $2="#define $2(skaddr,sksize) ($addr)"
394 $3="#define $3(skaddr,sksize) ($size)"
395 AC_SUBST($2)dnl
396 AC_SUBST($3)dnl
397 dnl #   display result indicator
398 AC_MSG_RESULT([$type])
399 dnl #   display results in detail
400 AC_MSG_VERBOSE([$]$2)
401 AC_MSG_VERBOSE([$]$3)
402 ])