1 
2 /* Test program to demonstrate valgrind breaking fcntl locks during
3  * mmap.  Feed it a r/w file, such as its own source code. */
4 
5 /* See bug 280965. */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <sys/mman.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <err.h>
15 
main(int argc,char * argv[])16 int main(int argc, char *argv[])
17 {
18 	struct flock fl;
19 	const char *file = /* argv[1]; */
20 			   "mmap_fcntl_bug.c";
21 	int fd, status;
22         off_t initial;
23 
24 	if (!file)
25 		errx(1, "Usage: %s <normal-file>", argv[0]);
26 
27 	fd = open(file, O_RDWR);
28 	if (fd < 0)
29 		err(1, "Opening %s", file);
30 
31         // reproduce bug 297991: mmap interferes with fd position
32         initial = lseek(fd, 123, SEEK_SET);
33         if (123 != initial)
34                 err(1, "initial off_t differs from 123 (TEST FAILED)");
35         if (lseek(fd, 0, SEEK_CUR) != 123)
36                 err(1, "zero offset from initial differs from 123 (TEST FAILED)");
37 
38 	fl.l_type = F_WRLCK;
39 	fl.l_whence = SEEK_SET;
40 	fl.l_start = 0;
41 	fl.l_len = 1;
42 
43 	/* I'm assuming no one else tries to lock this! */
44 	if (fcntl(fd, F_SETLK, &fl) != 0)
45 		err(1, "Locking %s", file);
46 
47 	/* If under valgrind, mmap re-opens and closes file, screwing us */
48 	if (mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0) == MAP_FAILED)
49 		err(1, "mmap of %s", file);
50         if (lseek(fd, 0, SEEK_CUR) != 123)
51                 errx(1, "zero offset from initial after mmap differs from 123 (TEST FAILED)");
52 
53 	switch (fork()) {
54 	case 0:
55 		/* Child.  Lock should fail. */
56 		if (fcntl(fd, F_SETLK, &fl) == 0)
57 			exit(1);
58 		exit(0);
59 	case -1:
60 		err(1, "Fork failed");
61 	}
62 
63 	if (wait(&status) == -1)
64 		 err(1, "Child vanished?");
65 
66 	if (!WIFEXITED(status))
67 		errx(1, "Child died with signal %i", WTERMSIG(status));
68 
69 	switch (WEXITSTATUS(status)) {
70 	case 1:
71 		errx(1, "Child got lock, we must have dropped it (TEST FAILED)");
72 	case 0:
73 		fprintf(stderr, "Child exited with zero (TEST PASSED).\n");
74 		return 0;
75 	default:
76 		errx(1, "Child weird exit status %i", WEXITSTATUS(status));
77 	}
78 }
79