Add possibility to set memory limit for binaries run via libSystem. This
authorAnton Korobeynikov <asl@math.spbu.ru>
Fri, 16 Feb 2007 19:11:07 +0000 (19:11 +0000)
committerAnton Korobeynikov <asl@math.spbu.ru>
Fri, 16 Feb 2007 19:11:07 +0000 (19:11 +0000)
is especially needed for bugpoint. This partly implements PR688

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@34349 91177308-0d34-0410-b5e6-96231b3b80d8

16 files changed:
autoconf/configure.ac
include/llvm/Config/config.h.in
include/llvm/System/Program.h
lib/Support/GraphWriter.cpp
lib/System/Unix/Program.inc
lib/System/Win32/Program.inc
tools/bugpoint/BugDriver.cpp
tools/bugpoint/BugDriver.h
tools/bugpoint/ExecutionDriver.cpp
tools/bugpoint/OptimizerDriver.cpp
tools/bugpoint/ToolRunner.cpp
tools/bugpoint/ToolRunner.h
tools/bugpoint/bugpoint.cpp
tools/llvm-ld/llvm-ld.cpp
tools/llvmc/CompilerDriver.cpp
tools/lto/lto.cpp

index ea67fea9fbc80525f1d2870377851cc8ae588628..ad73185f9665cc7372590f0dce14eb3da5e18187 100644 (file)
@@ -709,7 +709,8 @@ dnl===
 dnl===-----------------------------------------------------------------------===
 
 AC_CHECK_FUNCS([backtrace ceilf floorf roundf rintf nearbyintf getcwd ])
-AC_CHECK_FUNCS([getpagesize getrusage gettimeofday isatty mkdtemp mkstemp ])
+AC_CHECK_FUNCS([getpagesize getrusage getrlimit setrlimit gettimeofday])
+AC_CHECK_FUNCS([isatty mkdtemp mkstemp ])
 AC_CHECK_FUNCS([mktemp realpath sbrk setrlimit strdup strerror strerror_r ])
 AC_CHECK_FUNCS([strtoll strtoq sysconf malloc_zone_statistics ])
 AC_CHECK_FUNCS([setjmp longjmp sigsetjmp siglongjmp])
index 2e9731e1a4a1ff00f4b0fdc0b833a63144d9e53b..7a52010c686074a6448f59c034934b40181e93c9 100644 (file)
 /* Define to 1 if you have the `getpagesize' function. */
 #undef HAVE_GETPAGESIZE
 
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
 /* Define to 1 if you have the `getrusage' function. */
 #undef HAVE_GETRUSAGE
 
index 3c9230c9e067837575bd2362c7b567478b1084f8..cef3805370cd9b59b0ae93536188d0e325ef464c 100644 (file)
@@ -72,6 +72,10 @@ namespace sys {
           ///< expires, the child is killed and this call returns. If zero,
           ///< this function will wait until the child finishes or forever if
           ///< it doesn't.
+        unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount
+          ///< of memory can be allocated by process. If memory usage will be
+          ///< higher limit, the child is killed and this call returns. If zero -
+          ///< no memory limit.
         std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string
           ///< instance in which error messages will be returned. If the string 
           ///< is non-empty upon return an error occurred while invoking the
index ecf2bfdb9141054db6ef96c9fc70598332a5a91e..31d8d797bedbbb49c7335587d5a2b8ce021e7c99 100644 (file)
@@ -29,7 +29,7 @@ void llvm::DisplayGraph(const sys::Path &Filename) {
   args.push_back(0);
   
   cerr << "Running 'Graphviz' program... " << std::flush;
-  if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,&ErrMsg)) {
+  if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg)) {
     cerr << "Error viewing graph: " << ErrMsg << "\n";
   }
 #elif (HAVE_GV && HAVE_DOT)
@@ -49,7 +49,7 @@ void llvm::DisplayGraph(const sys::Path &Filename) {
   args.push_back(0);
   
   cerr << "Running 'dot' program... " << std::flush;
-  if (sys::Program::ExecuteAndWait(dot, &args[0],0,0,0,&ErrMsg)) {
+  if (sys::Program::ExecuteAndWait(dot, &args[0],0,0,0,0,&ErrMsg)) {
     cerr << "Error viewing graph: '" << ErrMsg << "\n";
   } else {
     cerr << " done. \n";
@@ -61,7 +61,7 @@ void llvm::DisplayGraph(const sys::Path &Filename) {
     args.push_back(0);
     
     ErrMsg.clear();
-    if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,&ErrMsg)) {
+    if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,0,&ErrMsg)) {
       cerr << "Error viewing graph: " << ErrMsg << "\n";
     }
   }
@@ -74,7 +74,7 @@ void llvm::DisplayGraph(const sys::Path &Filename) {
   args.push_back(0);
   
   cerr << "Running 'dotty' program... " << std::flush;
-  if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,&ErrMsg)) {
+  if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,0,&ErrMsg)) {
     cerr << "Error viewing graph: " << ErrMsg << "\n";
   } else {
 #ifdef __MINGW32__ // Dotty spawns another app and doesn't wait until it returns
index 5961dae5ad0e379c9df8db2b2027022eff733259..77d74a18c67735b123078758a4f57b39e2cecadd 100644 (file)
@@ -22,6 +22,9 @@
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 #if HAVE_SIGNAL_H
 #include <signal.h>
 #endif
@@ -106,12 +109,34 @@ static void TimeOutHandler(int Sig) {
   Timeout = true;
 }
 
+static void SetMemoryLimits (unsigned size)
+{
+#if HAVE_SYS_RESOURCE_H
+  struct rlimit r;
+  __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576;
+
+  // Heap size
+  getrlimit (RLIMIT_DATA, &r);
+  r.rlim_cur = limit;
+  setrlimit (RLIMIT_DATA, &r);
+  // Resident set size.
+  getrlimit (RLIMIT_RSS, &r);
+  r.rlim_cur = limit;
+  setrlimit (RLIMIT_RSS, &r);
+  // Virtual memory.
+  getrlimit (RLIMIT_AS, &r);
+  r.rlim_cur = limit;
+  setrlimit (RLIMIT_AS, &r);
+#endif
+}
+
 int 
 Program::ExecuteAndWait(const Path& path, 
                         const char** args,
                         const char** envp,
                         const Path** redirects,
                         unsigned secondsToWait,
+                        unsigned memoryLimit,
                         std::string* ErrMsg) 
 {
   if (!path.canExecute()) {
@@ -160,6 +185,11 @@ Program::ExecuteAndWait(const Path& path,
         }
       }
 
+      // Set memory limits
+      if (memoryLimit!=0) {
+        SetMemoryLimits(memoryLimit);
+      }
+      
       // Execute!
       if (envp != 0)
         execve (path.c_str(), (char** const)args, (char**)envp);
index e1ad155bb34d5fbffcf30d556f025914dec925d6..86e6d580634007707f52eb996c038a618f5954c5 100644 (file)
@@ -104,6 +104,7 @@ Program::ExecuteAndWait(const Path& path,
                         const char** envp,
                         const Path** redirects,
                         unsigned secondsToWait,
+                        unsigned memoryLimit,
                         std::string* ErrMsg) {
   if (!path.canExecute()) {
     if (ErrMsg)
index 2b4d35d142e819867bbbcdbefd5279562b028bd1..b2a8f030c5f4ebb5f4a1296aaa16879e649ea816 100644 (file)
@@ -64,10 +64,10 @@ std::string llvm::getPassesString(const std::vector<const PassInfo*> &Passes) {
 }
 
 BugDriver::BugDriver(const char *toolname, bool as_child, bool find_bugs,
-                     unsigned timeout)
+                     unsigned timeout, unsigned memlimit)
   : ToolName(toolname), ReferenceOutputFile(OutputFile),
     Program(0), Interpreter(0), cbe(0), gcc(0), run_as_child(as_child),
-    run_find_bugs(find_bugs), Timeout(timeout) {}
+    run_find_bugs(find_bugs), Timeout(timeout), MemoryLimit(memlimit) {}
 
 
 /// ParseInputFile - Given a bytecode or assembly input filename, parse and
index 3de7b055f94c7d29e5651de766d36c53fd0dc23f..ef8118c58f982ab8154e1695f008da70f461e621 100644 (file)
@@ -50,6 +50,7 @@ class BugDriver {
   bool run_as_child;
   bool run_find_bugs;
   unsigned Timeout;
+  unsigned MemoryLimit;
 
   // FIXME: sort out public/private distinctions...
   friend class ReducePassList;
@@ -57,7 +58,7 @@ class BugDriver {
 
 public:
   BugDriver(const char *toolname, bool as_child, bool find_bugs,
-            unsigned timeout);
+            unsigned timeout, unsigned memlimit);
 
   const std::string &getToolName() const { return ToolName; }
 
index 92e7737600426bcd87756976c206eb896690d005..f4a072b14aede9f0649b7c3e7ca348bc9f6dbe4e 100644 (file)
@@ -263,11 +263,11 @@ std::string BugDriver::executeProgram(std::string OutputFile,
       InterpreterSel == CBE_bug)
     RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
                                 OutputFile, AdditionalLinkerArgs, SharedObjs, 
-                                Timeout);
+                                Timeout, MemoryLimit);
   else 
     RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
                                 OutputFile, std::vector<std::string>(), 
-                                SharedObjs, Timeout);
+                                SharedObjs, Timeout, MemoryLimit);
 
   if (RetVal == -1) {
     std::cerr << "<timeout>";
index 374de26911456c147691df902fed054b79221e90..210f348f3546700a12e1e4e04356c71173abaf92 100644 (file)
@@ -194,7 +194,8 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes,
     prog = sys::Program::FindProgramByName("valgrind");
   else
     prog = tool;
-  int result = sys::Program::ExecuteAndWait(prog,args,0,0,Timeout,&ErrMsg);
+  int result = sys::Program::ExecuteAndWait(prog, args, 0, 0,
+                                            Timeout, MemoryLimit, &ErrMsg);
 
   // If we are supposed to delete the bytecode file or if the passes crashed,
   // remove it now.  This may fail if the file was never created, but that's ok.
index 35f27db9cabff58973ac40feaa803d35830d61a0..150155fc3db3c2cbfa21f54415161be8cfe98a3a 100644 (file)
@@ -32,7 +32,8 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath,
                                  const sys::Path &StdInFile,
                                  const sys::Path &StdOutFile,
                                  const sys::Path &StdErrFile,
-                                 unsigned NumSeconds = 0) {
+                                 unsigned NumSeconds = 0,
+                                 unsigned MemoryLimit = 0) {
   const sys::Path* redirects[3];
   redirects[0] = &StdInFile;
   redirects[1] = &StdOutFile;
@@ -46,7 +47,8 @@ static int RunProgramWithTimeout(const sys::Path &ProgramPath,
   }
 
   return
-    sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects, NumSeconds);
+    sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects,
+                                 NumSeconds, MemoryLimit);
 }
 
 
@@ -102,7 +104,8 @@ namespace {
                                const std::vector<std::string> &GCCArgs,
                                const std::vector<std::string> &SharedLibs =
                                std::vector<std::string>(),
-                               unsigned Timeout = 0);
+                               unsigned Timeout = 0,
+                               unsigned MemoryLimit = 0);
   };
 }
 
@@ -112,7 +115,8 @@ int LLI::ExecuteProgram(const std::string &Bytecode,
                         const std::string &OutputFile,
                         const std::vector<std::string> &GCCArgs,
                         const std::vector<std::string> &SharedLibs,
-                        unsigned Timeout) {
+                        unsigned Timeout,
+                        unsigned MemoryLimit) {
   if (!SharedLibs.empty())
     throw ToolExecutionError("LLI currently does not support "
                              "loading shared libraries.");
@@ -142,7 +146,7 @@ int LLI::ExecuteProgram(const std::string &Bytecode,
         );
   return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0],
       sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
-      Timeout);
+      Timeout, MemoryLimit);
 }
 
 // LLI create method - Try to find the LLI executable
@@ -209,7 +213,8 @@ int LLC::ExecuteProgram(const std::string &Bytecode,
                         const std::string &OutputFile,
                         const std::vector<std::string> &ArgsForGCC,
                         const std::vector<std::string> &SharedLibs,
-                        unsigned Timeout) {
+                        unsigned Timeout,
+                        unsigned MemoryLimit) {
 
   sys::Path OutputAsmFile;
   OutputCode(Bytecode, OutputAsmFile);
@@ -220,7 +225,8 @@ int LLC::ExecuteProgram(const std::string &Bytecode,
 
   // Assuming LLC worked, compile the result with GCC and run it.
   return gcc->ExecuteProgram(OutputAsmFile.toString(), Args, GCC::AsmFile,
-                             InputFile, OutputFile, GCCArgs, Timeout);
+                             InputFile, OutputFile, GCCArgs,
+                             Timeout, MemoryLimit);
 }
 
 /// createLLC - Try to find the LLC executable
@@ -265,7 +271,8 @@ namespace {
                                  std::vector<std::string>(),
                                const std::vector<std::string> &SharedLibs =
                                  std::vector<std::string>(), 
-                               unsigned Timeout =0 );
+                               unsigned Timeout =0,
+                               unsigned MemoryLimit =0);
   };
 }
 
@@ -275,7 +282,8 @@ int JIT::ExecuteProgram(const std::string &Bytecode,
                         const std::string &OutputFile,
                         const std::vector<std::string> &GCCArgs,
                         const std::vector<std::string> &SharedLibs,
-                        unsigned Timeout) {
+                        unsigned Timeout,
+                        unsigned MemoryLimit) {
   if (!GCCArgs.empty())
     throw ToolExecutionError("JIT does not support GCC Arguments.");
   // Construct a vector of parameters, incorporating those from the command-line
@@ -306,7 +314,7 @@ int JIT::ExecuteProgram(const std::string &Bytecode,
   DEBUG(std::cerr << "\nSending output to " << OutputFile << "\n");
   return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0],
       sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
-      Timeout);
+      Timeout, MemoryLimit);
 }
 
 /// createJIT - Try to find the LLI executable
@@ -370,7 +378,8 @@ int CBE::ExecuteProgram(const std::string &Bytecode,
                         const std::string &OutputFile,
                         const std::vector<std::string> &ArgsForGCC,
                         const std::vector<std::string> &SharedLibs,
-                        unsigned Timeout) {
+                        unsigned Timeout,
+                        unsigned MemoryLimit) {
   sys::Path OutputCFile;
   OutputCode(Bytecode, OutputCFile);
 
@@ -379,7 +388,8 @@ int CBE::ExecuteProgram(const std::string &Bytecode,
   std::vector<std::string> GCCArgs(ArgsForGCC);
   GCCArgs.insert(GCCArgs.end(),SharedLibs.begin(),SharedLibs.end());
   return gcc->ExecuteProgram(OutputCFile.toString(), Args, GCC::CFile,
-                             InputFile, OutputFile, GCCArgs, Timeout);
+                             InputFile, OutputFile, GCCArgs,
+                             Timeout, MemoryLimit);
 }
 
 /// createCBE - Try to find the 'llc' executable
@@ -412,7 +422,8 @@ int GCC::ExecuteProgram(const std::string &ProgramFile,
                         const std::string &InputFile,
                         const std::string &OutputFile,
                         const std::vector<std::string> &ArgsForGCC,
-                        unsigned Timeout ) {
+                        unsigned Timeout,
+                        unsigned MemoryLimit) {
   std::vector<const char*> GCCArgs;
 
   GCCArgs.push_back(GCCPath.c_str());
@@ -488,7 +499,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile,
   FileRemover OutputBinaryRemover(OutputBinary);
   return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
       sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
-      Timeout);
+      Timeout, MemoryLimit);
 }
 
 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
index e64d0054f0a71c2796bf43dd694786a935cafdc0..1ebccd860a0a166c3027962572ab167cc0f70685 100644 (file)
@@ -64,7 +64,8 @@ public:
                      const std::string &OutputFile,
                      const std::vector<std::string> &GCCArgs =
                          std::vector<std::string>(), 
-                     unsigned Timeout = 0);
+                     unsigned Timeout = 0,
+                     unsigned MemoryLimit = 0);
 
   /// MakeSharedObject - This compiles the specified file (which is either a .c
   /// file or a .s file) into a shared object.
@@ -124,7 +125,8 @@ public:
                                std::vector<std::string>(),
                              const std::vector<std::string> &SharedLibs =
                                std::vector<std::string>(),
-                             unsigned Timeout = 0) = 0;
+                             unsigned Timeout = 0,
+                             unsigned MemoryLimit = 0) = 0;
 };
 
 //===---------------------------------------------------------------------===//
@@ -156,7 +158,8 @@ public:
                                std::vector<std::string>(),
                              const std::vector<std::string> &SharedLibs =
                                std::vector<std::string>(),
-                             unsigned Timeout = 0);
+                             unsigned Timeout = 0,
+                             unsigned MemoryLimit = 0);
 
   /// OutputCode - Compile the specified program from bytecode to code
   /// understood by the GCC driver (either C or asm).  If the code generator
@@ -196,7 +199,8 @@ public:
                                std::vector<std::string>(),
                              const std::vector<std::string> &SharedLibs =
                                 std::vector<std::string>(),
-                             unsigned Timeout = 0);
+                             unsigned Timeout = 0,
+                             unsigned MemoryLimit = 0);
 
   virtual GCC::FileType OutputCode(const std::string &Bytecode,
                                    sys::Path &OutFile);
index 0cdbfd45adb881175711f7c52aa2cc98d21fbaf7..c345143a901db665f60fb70ea115141c2232977b 100644 (file)
@@ -46,6 +46,10 @@ TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"),
              cl::desc("Number of seconds program is allowed to run before it "
                       "is killed (default is 300s), 0 disables timeout"));
 
+static cl::opt<unsigned>
+MemoryLimit("mlimit", cl::init(100), cl::value_desc("MBytes"),
+             cl::desc("Maximum amount of memory to use. 0 disables check."));
+
 // The AnalysesList is automatically populated with registered Passes by the
 // PassNameParser.
 //
@@ -68,7 +72,7 @@ int main(int argc, char **argv) {
   sys::PrintStackTraceOnErrorSignal();
   sys::SetInterruptFunction(BugpointInterruptFunction);
   
-  BugDriver D(argv[0],AsChild,FindBugs,TimeoutValue);
+  BugDriver D(argv[0], AsChild, FindBugs, TimeoutValue, MemoryLimit);
   if (D.addSources(InputFilenames)) return 1;
   D.addPasses(PassList.begin(), PassList.end());
 
index bb1130bfd101940d9f715a357763dc5d2efb9bbf..207f0cbb4f422a43db0cfd3d248df3a166e62be3 100644 (file)
@@ -244,7 +244,7 @@ static int GenerateAssembly(const std::string &OutputFilename,
   args.push_back(InputFilename.c_str());
   args.push_back(0);
 
-  return sys::Program::ExecuteAndWait(llc,&args[0],0,0,0,&ErrMsg);
+  return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg);
 }
 
 /// GenerateCFile - generates a C source file from the specified bytecode file.
@@ -261,7 +261,7 @@ static int GenerateCFile(const std::string &OutputFile,
   args.push_back(OutputFile.c_str());
   args.push_back(InputFile.c_str());
   args.push_back(0);
-  return sys::Program::ExecuteAndWait(llc, &args[0],0,0,0,&ErrMsg);
+  return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg);
 }
 
 /// GenerateNative - generates a native object file from the
@@ -342,7 +342,7 @@ static int GenerateNative(const std::string &OutputFilename,
 
   // Run the compiler to assembly and link together the program.
   int R = sys::Program::ExecuteAndWait(
-      gcc, &args[0], (const char**)clean_env,0,0,&ErrMsg);
+    gcc, &args[0], (const char**)clean_env, 0, 0, 0, &ErrMsg);
   delete [] clean_env;
   return R;
 }
@@ -516,7 +516,7 @@ int main(int argc, char **argv, char **envp) {
           args[1] = RealBytecodeOutput.c_str();
           args[2] = tmp_output.c_str();
           args[3] = 0;
-          if (0 == sys::Program::ExecuteAndWait(prog, args, 0,0,0, &ErrMsg)) {
+          if (0 == sys::Program::ExecuteAndWait(prog, args, 0,0,0,0, &ErrMsg)) {
             if (tmp_output.isBytecodeFile()) {
               sys::Path target(RealBytecodeOutput);
               target.eraseFromDisk();
index a076a46525b98607827c18dea4b99b58ffbc57ca..c153df8ac48d3ab84de2547713844d67b1ae16b4 100644 (file)
@@ -499,14 +499,14 @@ private:
         Timer timer(action->program.toString());
         timer.startTimer();
         int resultCode = 
-          sys::Program::ExecuteAndWait(action->program, Args,0,0,0,&ErrMsg);
+          sys::Program::ExecuteAndWait(action->program, Args,0,0,0,0, &ErrMsg);
         timer.stopTimer();
         timer.print(timer,std::cerr);
         return resultCode;
       }
       else
         return 
-          sys::Program::ExecuteAndWait(action->program, Args, 0,0,0, &ErrMsg);
+          sys::Program::ExecuteAndWait(action->program, Args, 0,0,0,0, &ErrMsg);
     }
     return 0;
   }
index 730e7c22f7542f85b1fc772d160c6bfe8c0efca7..1f707444eec5741ba45b712aa2e0908a3ba79050 100644 (file)
@@ -458,7 +458,7 @@ LTO::optimizeModules(const std::string &OutputFilename,
   args.push_back(tmpAsmFilePath.c_str());
   args.push_back(0);
 
-  if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 1, &ErrMsg)) {
+  if (sys::Program::ExecuteAndWait(gcc, &args[0], 0, 0, 1, 0, &ErrMsg)) {
     cerr << "lto: " << ErrMsg << "\n";
     return LTO_ASM_FAILURE;
   }