1 | //===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file provides the generic Unix implementation of the Process class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "Unix.h" |
14 | #include "llvm/ADT/Hashing.h" |
15 | #include "llvm/ADT/StringRef.h" |
16 | #include "llvm/Config/config.h" |
17 | #include <mutex> |
18 | #include <optional> |
19 | #if HAVE_FCNTL_H |
20 | #include <fcntl.h> |
21 | #endif |
22 | #ifdef HAVE_SYS_TIME_H |
23 | #include <sys/time.h> |
24 | #endif |
25 | #ifdef HAVE_SYS_RESOURCE_H |
26 | #include <sys/resource.h> |
27 | #endif |
28 | #ifdef HAVE_SYS_STAT_H |
29 | #include <sys/stat.h> |
30 | #endif |
31 | #if HAVE_SIGNAL_H |
32 | #include <signal.h> |
33 | #endif |
34 | #if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2) |
35 | #include <malloc.h> |
36 | #endif |
37 | #if defined(HAVE_MALLCTL) |
38 | #include <malloc_np.h> |
39 | #endif |
40 | #ifdef HAVE_MALLOC_MALLOC_H |
41 | #include <malloc/malloc.h> |
42 | #endif |
43 | #ifdef HAVE_SYS_IOCTL_H |
44 | #include <sys/ioctl.h> |
45 | #endif |
46 | #ifdef HAVE_TERMIOS_H |
47 | #include <termios.h> |
48 | #endif |
49 | |
50 | //===----------------------------------------------------------------------===// |
51 | //=== WARNING: Implementation here must contain only generic UNIX code that |
52 | //=== is guaranteed to work on *all* UNIX variants. |
53 | //===----------------------------------------------------------------------===// |
54 | |
55 | using namespace llvm; |
56 | using namespace sys; |
57 | |
58 | static std::pair<std::chrono::microseconds, std::chrono::microseconds> |
59 | getRUsageTimes() { |
60 | #if defined(HAVE_GETRUSAGE) |
61 | struct rusage RU; |
62 | ::getrusage(RUSAGE_SELF, usage: &RU); |
63 | return {toDuration(TV: RU.ru_utime), toDuration(TV: RU.ru_stime)}; |
64 | #else |
65 | #ifndef __MVS__ // Exclude for MVS in case -pedantic is used |
66 | #warning Cannot get usage times on this platform |
67 | #endif |
68 | return {std::chrono::microseconds::zero(), std::chrono::microseconds::zero()}; |
69 | #endif |
70 | } |
71 | |
72 | Process::Pid Process::getProcessId() { |
73 | static_assert(sizeof(Pid) >= sizeof(pid_t), |
74 | "Process::Pid should be big enough to store pid_t" ); |
75 | return Pid(::getpid()); |
76 | } |
77 | |
78 | // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and |
79 | // offset in mmap(3) should be aligned to the AllocationGranularity. |
80 | Expected<unsigned> Process::getPageSize() { |
81 | #if defined(HAVE_GETPAGESIZE) |
82 | static const int page_size = ::getpagesize(); |
83 | #elif defined(HAVE_SYSCONF) |
84 | static long page_size = ::sysconf(_SC_PAGE_SIZE); |
85 | #else |
86 | #error Cannot get the page size on this machine |
87 | #endif |
88 | if (page_size == -1) |
89 | return errorCodeToError(EC: errnoAsErrorCode()); |
90 | |
91 | return static_cast<unsigned>(page_size); |
92 | } |
93 | |
94 | size_t Process::GetMallocUsage() { |
95 | #if defined(HAVE_MALLINFO2) |
96 | struct mallinfo2 mi; |
97 | mi = ::mallinfo2(); |
98 | return mi.uordblks; |
99 | #elif defined(HAVE_MALLINFO) |
100 | struct mallinfo mi; |
101 | mi = ::mallinfo(); |
102 | return mi.uordblks; |
103 | #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) |
104 | malloc_statistics_t Stats; |
105 | malloc_zone_statistics(malloc_default_zone(), &Stats); |
106 | return Stats.size_in_use; // darwin |
107 | #elif defined(HAVE_MALLCTL) |
108 | size_t alloc, sz; |
109 | sz = sizeof(size_t); |
110 | if (mallctl("stats.allocated" , &alloc, &sz, NULL, 0) == 0) |
111 | return alloc; |
112 | return 0; |
113 | #elif defined(HAVE_SBRK) |
114 | // Note this is only an approximation and more closely resembles |
115 | // the value returned by mallinfo in the arena field. |
116 | static char *StartOfMemory = reinterpret_cast<char *>(::sbrk(0)); |
117 | char *EndOfMemory = (char *)sbrk(0); |
118 | if (EndOfMemory != ((char *)-1) && StartOfMemory != ((char *)-1)) |
119 | return EndOfMemory - StartOfMemory; |
120 | return 0; |
121 | #else |
122 | #ifndef __MVS__ // Exclude for MVS in case -pedantic is used |
123 | #warning Cannot get malloc info on this platform |
124 | #endif |
125 | return 0; |
126 | #endif |
127 | } |
128 | |
129 | void Process::GetTimeUsage(TimePoint<> &elapsed, |
130 | std::chrono::nanoseconds &user_time, |
131 | std::chrono::nanoseconds &sys_time) { |
132 | elapsed = std::chrono::system_clock::now(); |
133 | std::tie(args&: user_time, args&: sys_time) = getRUsageTimes(); |
134 | } |
135 | |
136 | #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) |
137 | #include <mach/mach.h> |
138 | #endif |
139 | |
140 | // Some LLVM programs such as bugpoint produce core files as a normal part of |
141 | // their operation. To prevent the disk from filling up, this function |
142 | // does what's necessary to prevent their generation. |
143 | void Process::PreventCoreFiles() { |
144 | #if HAVE_SETRLIMIT |
145 | struct rlimit rlim; |
146 | getrlimit(RLIMIT_CORE, rlimits: &rlim); |
147 | #ifdef __linux__ |
148 | // On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it |
149 | // is being piped to a coredump handler such as systemd-coredumpd), the |
150 | // kernel ignores RLIMIT_CORE (since we aren't creating a file in the file |
151 | // system) except for the magic value of 1, which disables coredumps when |
152 | // piping. 1 byte is too small for any kind of valid core dump, so it |
153 | // also disables coredumps if kernel.core_pattern creates files directly. |
154 | // While most piped coredump handlers do respect the crashing processes' |
155 | // RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump |
156 | // due to a local patch that changes sysctl.d/50-coredump.conf to ignore |
157 | // the specified limit and instead use RLIM_INFINITY. |
158 | // |
159 | // The alternative to using RLIMIT_CORE=1 would be to use prctl() with the |
160 | // PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it |
161 | // impossible to attach a debugger. |
162 | rlim.rlim_cur = std::min<rlim_t>(a: 1, b: rlim.rlim_max); |
163 | #else |
164 | rlim.rlim_cur = 0; |
165 | #endif |
166 | setrlimit(RLIMIT_CORE, rlimits: &rlim); |
167 | #endif |
168 | |
169 | #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) |
170 | // Disable crash reporting on Mac OS X 10.0-10.4 |
171 | |
172 | // get information about the original set of exception ports for the task |
173 | mach_msg_type_number_t Count = 0; |
174 | exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; |
175 | exception_port_t OriginalPorts[EXC_TYPES_COUNT]; |
176 | exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; |
177 | thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; |
178 | kern_return_t err = task_get_exception_ports( |
179 | mach_task_self(), EXC_MASK_ALL, OriginalMasks, &Count, OriginalPorts, |
180 | OriginalBehaviors, OriginalFlavors); |
181 | if (err == KERN_SUCCESS) { |
182 | // replace each with MACH_PORT_NULL. |
183 | for (unsigned i = 0; i != Count; ++i) |
184 | task_set_exception_ports(mach_task_self(), OriginalMasks[i], |
185 | MACH_PORT_NULL, OriginalBehaviors[i], |
186 | OriginalFlavors[i]); |
187 | } |
188 | |
189 | // Disable crash reporting on Mac OS X 10.5 |
190 | signal(SIGABRT, _exit); |
191 | signal(SIGILL, _exit); |
192 | signal(SIGFPE, _exit); |
193 | signal(SIGSEGV, _exit); |
194 | signal(SIGBUS, _exit); |
195 | #endif |
196 | |
197 | coreFilesPrevented = true; |
198 | } |
199 | |
200 | std::optional<std::string> Process::GetEnv(StringRef Name) { |
201 | std::string NameStr = Name.str(); |
202 | const char *Val = ::getenv(name: NameStr.c_str()); |
203 | if (!Val) |
204 | return std::nullopt; |
205 | return std::string(Val); |
206 | } |
207 | |
208 | namespace { |
209 | class FDCloser { |
210 | public: |
211 | FDCloser(int &FD) : FD(FD), KeepOpen(false) {} |
212 | void keepOpen() { KeepOpen = true; } |
213 | ~FDCloser() { |
214 | if (!KeepOpen && FD >= 0) |
215 | ::close(fd: FD); |
216 | } |
217 | |
218 | private: |
219 | FDCloser(const FDCloser &) = delete; |
220 | void operator=(const FDCloser &) = delete; |
221 | |
222 | int &FD; |
223 | bool KeepOpen; |
224 | }; |
225 | } // namespace |
226 | |
227 | std::error_code Process::FixupStandardFileDescriptors() { |
228 | int NullFD = -1; |
229 | FDCloser FDC(NullFD); |
230 | const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; |
231 | for (int StandardFD : StandardFDs) { |
232 | struct stat st; |
233 | errno = 0; |
234 | if (RetryAfterSignal(Fail: -1, F&: ::fstat, As: StandardFD, As: &st) < 0) { |
235 | assert(errno && "expected errno to be set if fstat failed!" ); |
236 | // fstat should return EBADF if the file descriptor is closed. |
237 | if (errno != EBADF) |
238 | return errnoAsErrorCode(); |
239 | } |
240 | // if fstat succeeds, move on to the next FD. |
241 | if (!errno) |
242 | continue; |
243 | assert(errno == EBADF && "expected errno to have EBADF at this point!" ); |
244 | |
245 | if (NullFD < 0) { |
246 | // Call ::open in a lambda to avoid overload resolution in |
247 | // RetryAfterSignal when open is overloaded, such as in Bionic. |
248 | auto Open = [&]() { return ::open(file: "/dev/null" , O_RDWR); }; |
249 | if ((NullFD = RetryAfterSignal(Fail: -1, F: Open)) < 0) |
250 | return errnoAsErrorCode(); |
251 | } |
252 | |
253 | if (NullFD == StandardFD) |
254 | FDC.keepOpen(); |
255 | else if (dup2(fd: NullFD, fd2: StandardFD) < 0) |
256 | return errnoAsErrorCode(); |
257 | } |
258 | return std::error_code(); |
259 | } |
260 | |
261 | std::error_code Process::SafelyCloseFileDescriptor(int FD) { |
262 | // Create a signal set filled with *all* signals. |
263 | sigset_t FullSet, SavedSet; |
264 | if (sigfillset(set: &FullSet) < 0 || sigfillset(set: &SavedSet) < 0) |
265 | return errnoAsErrorCode(); |
266 | |
267 | // Atomically swap our current signal mask with a full mask. |
268 | #if LLVM_ENABLE_THREADS |
269 | if (int EC = pthread_sigmask(SIG_SETMASK, newmask: &FullSet, oldmask: &SavedSet)) |
270 | return std::error_code(EC, std::generic_category()); |
271 | #else |
272 | if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0) |
273 | return errnoAsErrorCode(); |
274 | #endif |
275 | // Attempt to close the file descriptor. |
276 | // We need to save the error, if one occurs, because our subsequent call to |
277 | // pthread_sigmask might tamper with errno. |
278 | int ErrnoFromClose = 0; |
279 | if (::close(fd: FD) < 0) |
280 | ErrnoFromClose = errno; |
281 | // Restore the signal mask back to what we saved earlier. |
282 | int EC = 0; |
283 | #if LLVM_ENABLE_THREADS |
284 | EC = pthread_sigmask(SIG_SETMASK, newmask: &SavedSet, oldmask: nullptr); |
285 | #else |
286 | if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0) |
287 | EC = errno; |
288 | #endif |
289 | // The error code from close takes precedence over the one from |
290 | // pthread_sigmask. |
291 | if (ErrnoFromClose) |
292 | return std::error_code(ErrnoFromClose, std::generic_category()); |
293 | return std::error_code(EC, std::generic_category()); |
294 | } |
295 | |
296 | bool Process::StandardInIsUserInput() { |
297 | return FileDescriptorIsDisplayed(STDIN_FILENO); |
298 | } |
299 | |
300 | bool Process::StandardOutIsDisplayed() { |
301 | return FileDescriptorIsDisplayed(STDOUT_FILENO); |
302 | } |
303 | |
304 | bool Process::StandardErrIsDisplayed() { |
305 | return FileDescriptorIsDisplayed(STDERR_FILENO); |
306 | } |
307 | |
308 | bool Process::FileDescriptorIsDisplayed(int fd) { |
309 | #if HAVE_ISATTY |
310 | return isatty(fd: fd); |
311 | #else |
312 | // If we don't have isatty, just return false. |
313 | return false; |
314 | #endif |
315 | } |
316 | |
317 | static unsigned getColumns() { |
318 | // If COLUMNS is defined in the environment, wrap to that many columns. |
319 | if (const char *ColumnsStr = std::getenv(name: "COLUMNS" )) { |
320 | int Columns = std::atoi(nptr: ColumnsStr); |
321 | if (Columns > 0) |
322 | return Columns; |
323 | } |
324 | |
325 | // We used to call ioctl TIOCGWINSZ to determine the width. It is considered |
326 | // unuseful. |
327 | return 0; |
328 | } |
329 | |
330 | unsigned Process::StandardOutColumns() { |
331 | if (!StandardOutIsDisplayed()) |
332 | return 0; |
333 | |
334 | return getColumns(); |
335 | } |
336 | |
337 | unsigned Process::StandardErrColumns() { |
338 | if (!StandardErrIsDisplayed()) |
339 | return 0; |
340 | |
341 | return getColumns(); |
342 | } |
343 | |
344 | static bool terminalHasColors() { |
345 | // Check if the current terminal is one of terminals that are known to support |
346 | // ANSI color escape codes. |
347 | if (const char *TermStr = std::getenv(name: "TERM" )) { |
348 | return StringSwitch<bool>(TermStr) |
349 | .Case(S: "ansi" , Value: true) |
350 | .Case(S: "cygwin" , Value: true) |
351 | .Case(S: "linux" , Value: true) |
352 | .StartsWith(S: "screen" , Value: true) |
353 | .StartsWith(S: "xterm" , Value: true) |
354 | .StartsWith(S: "vt100" , Value: true) |
355 | .StartsWith(S: "rxvt" , Value: true) |
356 | .EndsWith(S: "color" , Value: true) |
357 | .Default(Value: false); |
358 | } |
359 | |
360 | return false; |
361 | } |
362 | |
363 | bool Process::FileDescriptorHasColors(int fd) { |
364 | // A file descriptor has colors if it is displayed and the terminal has |
365 | // colors. |
366 | return FileDescriptorIsDisplayed(fd) && terminalHasColors(); |
367 | } |
368 | |
369 | bool Process::StandardOutHasColors() { |
370 | return FileDescriptorHasColors(STDOUT_FILENO); |
371 | } |
372 | |
373 | bool Process::StandardErrHasColors() { |
374 | return FileDescriptorHasColors(STDERR_FILENO); |
375 | } |
376 | |
377 | void Process::UseANSIEscapeCodes(bool /*enable*/) { |
378 | // No effect. |
379 | } |
380 | |
381 | bool Process::ColorNeedsFlush() { |
382 | // No, we use ANSI escape sequences. |
383 | return false; |
384 | } |
385 | |
386 | const char *Process::OutputColor(char code, bool bold, bool bg) { |
387 | return colorcodes[bg ? 1 : 0][bold ? 1 : 0][code & 15]; |
388 | } |
389 | |
390 | const char *Process::OutputBold(bool bg) { return "\033[1m" ; } |
391 | |
392 | const char *Process::OutputReverse() { return "\033[7m" ; } |
393 | |
394 | const char *Process::ResetColor() { return "\033[0m" ; } |
395 | |
396 | #if !HAVE_DECL_ARC4RANDOM |
397 | static unsigned GetRandomNumberSeed() { |
398 | // Attempt to get the initial seed from /dev/urandom, if possible. |
399 | int urandomFD = open(file: "/dev/urandom" , O_RDONLY); |
400 | |
401 | if (urandomFD != -1) { |
402 | unsigned seed; |
403 | // Don't use a buffered read to avoid reading more data |
404 | // from /dev/urandom than we need. |
405 | int count = read(fd: urandomFD, buf: (void *)&seed, nbytes: sizeof(seed)); |
406 | |
407 | close(fd: urandomFD); |
408 | |
409 | // Return the seed if the read was successful. |
410 | if (count == sizeof(seed)) |
411 | return seed; |
412 | } |
413 | |
414 | // Otherwise, swizzle the current time and the process ID to form a reasonable |
415 | // seed. |
416 | const auto Now = std::chrono::high_resolution_clock::now(); |
417 | return hash_combine(args: Now.time_since_epoch().count(), args: ::getpid()); |
418 | } |
419 | #endif |
420 | |
421 | unsigned llvm::sys::Process::GetRandomNumber() { |
422 | #if HAVE_DECL_ARC4RANDOM |
423 | return arc4random(); |
424 | #else |
425 | static int x = (static_cast<void>(::srand(seed: GetRandomNumberSeed())), 0); |
426 | (void)x; |
427 | return ::rand(); |
428 | #endif |
429 | } |
430 | |
431 | [[noreturn]] void Process::ExitNoCleanup(int RetCode) { _Exit(status: RetCode); } |
432 | |