summaryrefslogtreecommitdiff
path: root/minix/tests/test62.c
blob: 348d0353d605b90727bebf9a196fdf9d00335fe0 (plain)
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
/* FPU state corruption test. This used to be able to crash the kernel. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <machine/fpu.h>

int max_error = 1;
#include "common.h"


double state = 2.0;
static int count;

static void use_fpu(int n)
{
  state += (double) n * 0.5;
}

static void crashed(int sig)
{
  exit(EXIT_SUCCESS);
}

static void handler(int sig, int code, struct sigcontext *sc)
{
  memset(&sc->sc_fpu_state, count, sizeof(sc->sc_fpu_state));
}

int main(void)
{
  int status;

  start(62);
  subtest = 0;

  signal(SIGUSR1, (void (*)(int)) handler);

  /* Initialize the FPU state. This state is inherited, too. */
  use_fpu(-1);

  for (count = 0; count <= 255; count++) {
	switch (fork()) {
	case -1:
		e(1);

		break;

	case 0:
		signal(SIGFPE, crashed);

		/* Load bad state into the kernel. */
		if (kill(getpid(), SIGUSR1)) e(2);

		/* Let the kernel restore the state. */
		use_fpu(count);

		exit(EXIT_SUCCESS);

	default:
		/* We cannot tell exactly whether what happened is correct or
		 * not -- certainly not in a platform-independent way. However,
		 * if the whole system keeps running, that's good enough.
		 */
		(void) wait(&status);
	}
  }

  if (state <= 1.4 || state >= 1.6) e(3);

  quit();

  return 0;
}