diff options
author | Chris Lattner <sabre@nondot.org> | 2002-12-23 23:50:16 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2002-12-23 23:50:16 +0000 |
commit | 4a10645c70199c8d8567fbc46312158c419720ab (patch) | |
tree | e13bf7470dd68952c31bcefeb9c899d8a944638b /support/lib/Support/SystemUtils.cpp | |
parent | 218e26ef3583cc3270f5f2a2b9cb1025e5b05ebe (diff) |
New files for miscompilation detection
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5120 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'support/lib/Support/SystemUtils.cpp')
-rw-r--r-- | support/lib/Support/SystemUtils.cpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/support/lib/Support/SystemUtils.cpp b/support/lib/Support/SystemUtils.cpp new file mode 100644 index 0000000000..5483f80958 --- /dev/null +++ b/support/lib/Support/SystemUtils.cpp @@ -0,0 +1,189 @@ +//===- SystemUtils.h - Utilities to do low-level system stuff --*- C++ -*--===// +// +// This file contains functions used to do a variety of low-level, often +// system-specific, tasks. +// +//===----------------------------------------------------------------------===// + +#include "SystemUtils.h" +#include <algorithm> +#include <fstream> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/wait.h> +#include <unistd.h> +#include <errno.h> + +/// removeFile - Delete the specified file +/// +void removeFile(const std::string &Filename) { + unlink(Filename.c_str()); +} + +/// getUniqueFilename - Return a filename with the specified prefix. If the +/// file does not exist yet, return it, otherwise add a suffix to make it +/// unique. +/// +std::string getUniqueFilename(const std::string &FilenameBase) { + if (!std::ifstream(FilenameBase.c_str())) + return FilenameBase; // Couldn't open the file? Use it! + + // Create a pattern for mkstemp... + char *FNBuffer = (char*)alloca(FilenameBase.size()+8); + strcpy(FNBuffer, FilenameBase.c_str()); + strcpy(FNBuffer+FilenameBase.size(), "-XXXXXX"); + + // Agree on a temporary file name to use.... + int TempFD; + if ((TempFD = mkstemp(FNBuffer)) == -1) { + std::cerr << "bugpoint: ERROR: Cannot create temporary file in the current " + << " directory!\n"; + exit(1); + } + + // We don't need to hold the temp file descriptor... we will trust that noone + // will overwrite/delete the file while we are working on it... + close(TempFD); + return FNBuffer; +} + +/// isExecutableFile - This function returns true if the filename specified +/// exists and is executable. +/// +bool isExecutableFile(const std::string &ExeFileName) { + struct stat Buf; + if (stat(ExeFileName.c_str(), &Buf)) + return false; // Must not be executable! + + if (!(Buf.st_mode & S_IFREG)) + return false; // Not a regular file? + + if (Buf.st_uid == getuid()) // Owner of file? + return Buf.st_mode & S_IXUSR; + else if (Buf.st_gid == getgid()) // In group of file? + return Buf.st_mode & S_IXGRP; + else // Unrelated to file? + return Buf.st_mode & S_IXOTH; +} + + +// FindExecutable - Find a named executable, giving the argv[0] of bugpoint. +// This assumes the executable is in the same directory as bugpoint itself. +// If the executable cannot be found, return an empty string. +// +std::string FindExecutable(const std::string &ExeName, + const std::string &BugPointPath) { + // First check the directory that bugpoint is in. We can do this if + // BugPointPath contains at least one / character, indicating that it is a + // relative path to bugpoint itself. + // + std::string Result = BugPointPath; + while (!Result.empty() && Result[Result.size()-1] != '/') + Result.erase(Result.size()-1, 1); + + if (!Result.empty()) { + Result += ExeName; + if (isExecutableFile(Result)) return Result; // Found it? + } + + // Okay, if the path to bugpoint didn't tell us anything, try using the PATH + // environment variable. + const char *PathStr = getenv("PATH"); + if (PathStr == 0) return ""; + + // Now we have a colon seperated list of directories to search... try them... + unsigned PathLen = strlen(PathStr); + while (PathLen) { + // Find the first colon... + const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); + + // Check to see if this first directory contains the executable... + std::string FilePath = std::string(PathStr, Colon) + '/' + ExeName; + if (isExecutableFile(FilePath)) + return FilePath; // Found the executable! + + // Nope it wasn't in this directory, check the next range! + PathLen -= Colon-PathStr; + PathStr = Colon; + while (*PathStr == ':') { // Advance past colons + PathStr++; + PathLen--; + } + } + + // If we fell out, we ran out of directories in PATH to search, return failure + return ""; +} + +static void RedirectFD(const std::string &File, int FD) { + if (File.empty()) return; // Noop + + // Open the file + int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); + if (InFD == -1) { + std::cerr << "Error opening file '" << File << "' for " + << (FD == 0 ? "input" : "output") << "!\n"; + exit(1); + } + + dup2(InFD, FD); // Install it as the requested FD + close(InFD); // Close the original FD +} + +/// RunProgramWithTimeout - This function executes the specified program, with +/// the specified null-terminated argument array, with the stdin/out/err fd's +/// redirected, with a timeout specified on the commandline. This terminates +/// the calling program if there is an error executing the specified program. +/// It returns the return value of the program, or -1 if a timeout is detected. +/// +int RunProgramWithTimeout(const std::string &ProgramPath, const char **Args, + const std::string &StdInFile, + const std::string &StdOutFile, + const std::string &StdErrFile) { + + // FIXME: install sigalarm handler here for timeout... + + int Child = fork(); + switch (Child) { + case -1: + std::cerr << "ERROR forking!\n"; + exit(1); + case 0: // Child + RedirectFD(StdInFile, 0); // Redirect file descriptors... + RedirectFD(StdOutFile, 1); + RedirectFD(StdErrFile, 2); + + execv(ProgramPath.c_str(), (char *const *)Args); + std::cerr << "Error executing program '" << ProgramPath; + for (; *Args; ++Args) + std::cerr << " " << *Args; + exit(1); + + default: break; + } + + // Make sure all output has been written while waiting + std::cout << std::flush; + + int Status; + if (wait(&Status) != Child) { + if (errno == EINTR) { + static bool FirstTimeout = true; + if (FirstTimeout) { + std::cout << + "*** Program execution timed out! This mechanism is designed to handle\n" + " programs stuck in infinite loops gracefully. The -timeout option\n" + " can be used to change the timeout threshold or disable it completely\n" + " (with -timeout=0). This message is only displayed once.\n"; + FirstTimeout = false; + } + return -1; // Timeout detected + } + + std::cerr << "Error waiting for child process!\n"; + exit(1); + } + return Status; +} |