diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
index 793c65dbafdf21ccbce6b88a4fc868c5d56baa8e..804c838232cb4569c843cd91ed9a93e941624491 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
@@ -27,6 +27,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
+import java.util.concurrent.TimeUnit;
 
 import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RVersionNumber;
@@ -50,6 +51,8 @@ public class GnuROneShotRSession implements RSession {
     private static final String[] GNUR_COMMANDLINE = new String[]{"R", "--vanilla", "--slave", "--silent"};
     private static final String FASTR_TESTGEN_GNUR = "FASTR_TESTGEN_GNUR";
     private static final String NATIVE_PROJECT = "com.oracle.truffle.r.native";
+    private static final int DEFAULT_TIMEOUT_MINS = 5;
+    private static int timeoutMins = DEFAULT_TIMEOUT_MINS;
 
     //@formatter:off
     protected static final String GNUR_OPTIONS =
@@ -65,6 +68,14 @@ public class GnuROneShotRSession implements RSession {
     protected static byte[] QUIT = "q()\n".getBytes();
 
     protected Process createGnuR() throws IOException {
+        String timeout = System.getenv("FASTR_TESTGEN_TIMEOUT");
+        if (timeout != null) {
+            try {
+                timeoutMins = Integer.parseInt(timeout);
+            } catch (NumberFormatException ex) {
+                System.err.println("ignoring invalid value for FASTR_TESTGEN_TIMEOUT");
+            }
+        }
         String testGenGnuR = System.getenv(FASTR_TESTGEN_GNUR);
         if (testGenGnuR != null) {
             if (testGenGnuR.length() == 0 || testGenGnuR.equals("internal")) {
@@ -93,24 +104,21 @@ public class GnuROneShotRSession implements RSession {
     }
 
     @Override
-    public String eval(String expression, ContextInfo contextInfo, boolean longTimeout) {
+    public String eval(String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable {
         if (expression.contains("library(") && !TestBase.generatingExpected()) {
             System.out.println("==============================================");
             System.out.println("LIBRARY LOADING WHILE CREATING EXPECTED OUTPUT");
             System.out.println("creating expected output for these tests only works during test output");
             System.out.println("generation (mx rtestgen), and will otherwise create corrupted output.");
         }
-        try {
-            Process p = createGnuR();
-            InputStream gnuRoutput = p.getInputStream();
-            OutputStream gnuRinput = p.getOutputStream();
-            send(gnuRinput, expression.getBytes(), NL, QUIT);
-            p.waitFor();
-            return readAvailable(gnuRoutput);
-        } catch (IOException | InterruptedException ex) {
-            System.err.print("exception: " + ex);
-            return null;
+        Process p = createGnuR();
+        InputStream gnuRoutput = p.getInputStream();
+        OutputStream gnuRinput = p.getOutputStream();
+        send(gnuRinput, expression.getBytes(), NL, QUIT);
+        if (!p.waitFor(timeoutMins, TimeUnit.MINUTES)) {
+            throw new RuntimeException(String.format("GNU R process timed out on: '%s'\n", expression));
         }
+        return readAvailable(gnuRoutput);
     }
 
     protected void send(OutputStream gnuRinput, byte[]... data) throws IOException {
@@ -125,8 +133,4 @@ public class GnuROneShotRSession implements RSession {
         return "GnuR one-shot";
     }
 
-    public static void main(String[] args) {
-        String testGenGnuR = System.getenv(FASTR_TESTGEN_GNUR);
-        System.out.printf("%s='%s'%n", FASTR_TESTGEN_GNUR, testGenGnuR);
-    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java
index e42c022411ae2fccc7273fc42ac9d5be625249ff..954a0b268d3a2eb928b8ac6d781caea86e670596 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java
@@ -34,6 +34,9 @@ public interface RSession {
      * If {@code contextInfo is non-null} it is used for the evaluation, else the choice is left to
      * the implementation. If the implementation uses timeouts, {@code longTimeout} indicates that
      * this evaluation is expected to take (much) longer than normal.
+     *
+     * This result will always be non-null or an exception will be thrown in, say, a timeout
+     * occurring.
      */
     String eval(String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable;