1 | // |
2 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
3 | // See https://llvm.org/LICENSE.txt for license information. |
4 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
5 | |
6 | /* |
7 | * fail.c |
8 | * testObjects |
9 | * |
10 | * Created by Blaine Garst on 9/16/08. |
11 | * |
12 | */ |
13 | #include <stdio.h> |
14 | #include <unistd.h> |
15 | #include <fcntl.h> |
16 | #include <string.h> |
17 | #include <stdlib.h> |
18 | #include <stdbool.h> |
19 | |
20 | |
21 | bool readfile(char *buffer, const char *from) { |
22 | int fd = open(file: from, oflag: 0); |
23 | if (fd < 0) return false; |
24 | int count = read(fd: fd, buf: buffer, nbytes: 512); |
25 | if (count < 0) return false; |
26 | buffer[count] = 0; // zap newline |
27 | return true; |
28 | } |
29 | |
30 | // basic idea, take compiler args, run compiler, and verify that expected failure matches any existing one |
31 | |
32 | int main(int argc, char *argv[]) { |
33 | if (argc == 1) return 0; |
34 | char *copy[argc+1]; // make a copy |
35 | // find and strip off -e "errorfile" |
36 | char *errorfile = NULL; |
37 | int counter = 0, i = 0; |
38 | for (i = 1; i < argc; ++i) { // skip 0 arg which is "fail" |
39 | if (!strncmp(s1: argv[i], s2: "-e" , n: 2)) { |
40 | errorfile = argv[++i]; |
41 | } |
42 | else { |
43 | copy[counter++] = argv[i]; |
44 | } |
45 | } |
46 | copy[counter] = NULL; |
47 | pid_t child = fork(); |
48 | char buffer[512]; |
49 | if (child == 0) { |
50 | // in child |
51 | sprintf(s: buffer, format: "/tmp/errorfile_%d" , getpid()); |
52 | close(fd: 1); |
53 | int fd = creat(file: buffer, mode: 0777); |
54 | if (fd != 1) { |
55 | fprintf(stderr, format: "didn't open custom error file %s as 1, got %d\n" , buffer, fd); |
56 | exit(status: 1); |
57 | } |
58 | close(fd: 2); |
59 | dup(fd: 1); |
60 | int result = execv(path: copy[0], argv: copy); |
61 | exit(status: 10); |
62 | } |
63 | if (child < 0) { |
64 | printf(format: "fork failed\n" ); |
65 | exit(status: 1); |
66 | } |
67 | int status = 0; |
68 | pid_t deadchild = wait(&status); |
69 | if (deadchild != child) { |
70 | printf(format: "wait got %d instead of %d\n" , deadchild, child); |
71 | exit(status: 1); |
72 | } |
73 | if (WEXITSTATUS(status) == 0) { |
74 | printf(format: "compiler exited normally, not good under these circumstances\n" ); |
75 | exit(status: 1); |
76 | } |
77 | //printf("exit status of child %d was %d\n", child, WEXITSTATUS(status)); |
78 | sprintf(s: buffer, format: "/tmp/errorfile_%d" , child); |
79 | if (errorfile) { |
80 | //printf("ignoring error file: %s\n", errorfile); |
81 | char desired[512]; |
82 | char got[512]; |
83 | bool gotErrorFile = readfile(buffer: desired, from: errorfile); |
84 | bool gotOutput = readfile(buffer: got, from: buffer); |
85 | if (!gotErrorFile && gotOutput) { |
86 | printf(format: "didn't read errorfile %s, it should have something from\n*****\n%s\n*****\nin it.\n" , |
87 | errorfile, got); |
88 | exit(status: 1); |
89 | } |
90 | else if (gotErrorFile && gotOutput) { |
91 | char *where = strstr(haystack: got, needle: desired); |
92 | if (!where) { |
93 | printf(format: "didn't find contents of %s in %s\n" , errorfile, buffer); |
94 | exit(status: 1); |
95 | } |
96 | } |
97 | else { |
98 | printf(format: "errorfile %s and output %s inconsistent\n" , errorfile, buffer); |
99 | exit(status: 1); |
100 | } |
101 | } |
102 | unlink(name: buffer); |
103 | printf(format: "success\n" ); |
104 | exit(status: 0); |
105 | } |
106 | |
107 | |