summaryrefslogtreecommitdiff
path: root/lib/Support/SystemUtils.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2002-12-23 23:50:16 +0000
committerChris Lattner <sabre@nondot.org>2002-12-23 23:50:16 +0000
commit4a10645c70199c8d8567fbc46312158c419720ab (patch)
treee13bf7470dd68952c31bcefeb9c899d8a944638b /lib/Support/SystemUtils.cpp
parent218e26ef3583cc3270f5f2a2b9cb1025e5b05ebe (diff)
downloadllvm-4a10645c70199c8d8567fbc46312158c419720ab.tar.gz
llvm-4a10645c70199c8d8567fbc46312158c419720ab.tar.bz2
llvm-4a10645c70199c8d8567fbc46312158c419720ab.tar.xz
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 'lib/Support/SystemUtils.cpp')
-rw-r--r--lib/Support/SystemUtils.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp
new file mode 100644
index 0000000000..5483f80958
--- /dev/null
+++ b/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;
+}