From 54464f10a777def2352b81b554610d3fe8d58a4e Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Thu, 21 Sep 2017 16:39:32 +0200
Subject: [PATCH] Fix: Disable R_ReleaseObject in shutdown phase to prevent
 SIGSEGV.

---
 .../r/ffi/impl/llvm/TruffleLLVM_Base.java     | 18 ++++++++++
 .../r/ffi/impl/managed/Managed_Base.java      | 13 +++++++
 .../truffle/r/ffi/impl/nfi/NFIContext.java    | 12 +++++++
 .../r/ffi/impl/nfi/NativeFunction.java        |  3 +-
 .../r/ffi/impl/nfi/TruffleNFI_Base.java       | 18 ++++++++++
 .../Rinternals_truffle_common.h               |  8 +++--
 .../fficall/src/truffle_nfi/rffiutils.c       | 10 ++++++
 .../fficall/src/truffle_nfi/rffiutils.h       |  4 +++
 .../truffle/r/runtime/context/RContext.java   |  9 +++++
 .../truffle/r/runtime/ffi/BaseRFFI.java       | 34 +++++++++++++++++++
 10 files changed, 125 insertions(+), 4 deletions(-)

diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
index 3cd51bce2d..22f48ef2cc 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
@@ -223,6 +223,19 @@ public class TruffleLLVM_Base implements BaseRFFI {
         }
     }
 
+    private static class TruffleLLVM_SetShutdownFlagNode extends TruffleLLVM_DownCallNode implements SetShutdownFlagNode {
+
+        @Override
+        protected NativeFunction getFunction() {
+            return NativeFunction.set_shutdown_phase;
+        }
+
+        @Override
+        public void execute(boolean value) {
+            call(value ? 1 : 0);
+        }
+    }
+
     @Override
     public GetpidNode createGetpidNode() {
         return new TruffleLLVM_GetpidNode();
@@ -272,4 +285,9 @@ public class TruffleLLVM_Base implements BaseRFFI {
     public GlobNode createGlobNode() {
         return new TruffleLLVM_GlobNode();
     }
+
+    @Override
+    public SetShutdownFlagNode createSetShutdownFlagNode() {
+        return new TruffleLLVM_SetShutdownFlagNode();
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
index 20c7d3f17d..9e95b85b6a 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
@@ -200,4 +200,17 @@ public class Managed_Base implements BaseRFFI {
     public GlobNode createGlobNode() {
         return null;
     }
+
+    private static final class ManagedSetShutdownFlagNode extends Node implements SetShutdownFlagNode {
+    
+        @Override
+        public void execute(boolean value) {
+            // do nothing
+        }
+    }
+
+    @Override
+    public SetShutdownFlagNode createSetShutdownFlagNode() {
+        return new ManagedSetShutdownFlagNode();
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java
index 7122102401..47f28cbce9 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
 import com.oracle.truffle.r.ffi.impl.common.LibPaths;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIContext;
@@ -49,9 +50,20 @@ class NFIContext extends RFFIContext {
             // force initialization of NFI
             DLLRFFI.DLOpenRootNode.create(context).call(librffiPath, false, false);
         }
+        if (RContext.getContextCnt() == 0) {
+            BaseRFFI.SetShutdownFlagRootNode.create().getCallTarget().call(false);
+        }
         return this;
     }
 
+    @Override
+    public void beforeDispose(RContext context) {
+        if (RContext.getContextCnt() == 1) {
+            BaseRFFI.SetShutdownFlagRootNode.create().getCallTarget().call(true);
+        }
+        super.beforeDispose(context);
+    }
+
     @Override
     public void afterDowncall() {
         for (Long ptr : transientAllocations) {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NativeFunction.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NativeFunction.java
index cf1c2d76c3..1e8dd4776e 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NativeFunction.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NativeFunction.java
@@ -78,7 +78,8 @@ public enum NativeFunction {
     dqrls("([double], sint32, sint32, [double], sint32, double, [double], [double], [double], [sint32], [sint32], [double], [double]): void", "call_misc_"),
     // stats
     fft_factor("(sint32, [sint32], [sint32]): void", TruffleNFI_Utils::lookupAndBindStats),
-    fft_work("([double], sint32, sint32, sint32, sint32, [double], [sint32]): sint32", TruffleNFI_Utils::lookupAndBindStats);
+    fft_work("([double], sint32, sint32, sint32, sint32, [double], [sint32]): sint32", TruffleNFI_Utils::lookupAndBindStats),
+    set_shutdown_phase("(uint8): void", TruffleNFI_Utils::lookupAndBind);
 
     private final int argumentCount;
     private final String signature;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
index c38173bfd4..69b7d456b2 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
@@ -213,6 +213,19 @@ public class TruffleNFI_Base implements BaseRFFI {
         }
     }
 
+    private static class TruffleNFI_SetShutdownFlagNode extends TruffleNFI_DownCallNode implements SetShutdownFlagNode {
+
+        @Override
+        protected NativeFunction getFunction() {
+            return NativeFunction.set_shutdown_phase;
+        }
+
+        @Override
+        public void execute(boolean value) {
+            call(value ? 1 : 0);
+        }
+    }
+
     @Override
     public GetpidNode createGetpidNode() {
         return new TruffleNFI_GetpidNode();
@@ -262,4 +275,9 @@ public class TruffleNFI_Base implements BaseRFFI {
     public GlobNode createGlobNode() {
         return new TruffleNFI_GlobNode();
     }
+
+    @Override
+    public SetShutdownFlagNode createSetShutdownFlagNode() {
+        return new TruffleNFI_SetShutdownFlagNode();
+    }
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
index 8460b04e7b..940cd21ab0 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
@@ -828,8 +828,8 @@ void SET_PRCODE(SEXP x, SEXP v) {
 }
 
 int TRUELENGTH(SEXP x) {
-    TRACE0();
-    unimplemented("unimplemented");
+    TRACE(TARGp, x);
+    // TODO do not throw an error for now
     return 0;
 }
 
@@ -1342,7 +1342,9 @@ void R_PreserveObject(SEXP x) {
 
 void R_ReleaseObject(SEXP x) {
     TRACE0();
-    ((call_R_ReleaseObject) callbacks[R_ReleaseObject_x])(x);
+    if(!is_shutdown_phase()) {
+    	((call_R_ReleaseObject) callbacks[R_ReleaseObject_x])(x);
+    }
 }
 
 void R_dot_Last(void) {
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.c
index 12c143c346..be3bf7cf24 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.c
@@ -41,6 +41,8 @@ void init_utils(TruffleEnv *env) {
     }
 }
 
+static unsigned char shutdown_phase = 0;
+
 #define ERROR_JMP_BUF_STACK_SIZE 32
 static jmp_buf *callErrorJmpBufStack[ERROR_JMP_BUF_STACK_SIZE];
 static int callErrorJmpBufStackIndex = 0;
@@ -79,6 +81,14 @@ static void popJmpBuf() {
     popJmpBuf();                    \
     return result;
 
+void set_shutdown_phase(unsigned char value) {
+	shutdown_phase = value;
+}
+
+int is_shutdown_phase() {
+	return shutdown_phase;
+}
+
 void dot_call_void0(callvoid0func fun) {
     DO_CALL_VOID(fun());
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h
index 8de8be4ec3..fc9621f2dc 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/rffiutils.h
@@ -53,6 +53,10 @@ typedef void (*callvoid0func)(void);
 
 typedef void (*callvoid1func)(SEXP arg1);
 
+void set_shutdown_phase(unsigned char value);
+
+int is_shutdown_phase();
+
 void dot_call_void0(callvoid0func);
 
 void dot_call_void1(callvoid1func, SEXP);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index 265f759518..2232e1e758 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -48,6 +48,7 @@ import java.util.TimeZone;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Supplier;
 
 import com.oracle.truffle.api.Assumption;
@@ -292,6 +293,8 @@ public final class RContext implements RTruffleObject {
      */
     private static boolean embedded;
 
+    private static final AtomicInteger CONTEXT_CNT = new AtomicInteger(0);
+
     /*
      * Workarounds to finesse project circularities between runtime/nodes.
      */
@@ -372,6 +375,10 @@ public final class RContext implements RTruffleObject {
         return embedded;
     }
 
+    public static int getContextCnt() {
+        return CONTEXT_CNT.get();
+    }
+
     /**
      * Sets the fields that do not depend on complex initialization.
      *
@@ -523,6 +530,7 @@ public final class RContext implements RTruffleObject {
         if (initial && !embedded) {
             initialContextInitialized = true;
         }
+        CONTEXT_CNT.incrementAndGet();
         return this;
     }
 
@@ -574,6 +582,7 @@ public final class RContext implements RTruffleObject {
             if (contextKind == ContextKind.SHARE_PARENT_RW) {
                 parentContext.sharedChild = null;
             }
+            CONTEXT_CNT.decrementAndGet();
             state = EnumSet.of(State.DISPOSED);
 
             this.allocationReporter.removePropertyChangeListener(ALLOCATION_ACTIVATION_LISTENER);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
index 2a6ad69190..6ae84cd476 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.NodeInterface;
+import com.oracle.truffle.r.runtime.data.RNull;
 
 /**
  * A statically typed interface to exactly those native functions required by the R {@code base}
@@ -163,6 +164,14 @@ public interface BaseRFFI {
         }
     }
 
+    interface SetShutdownFlagNode extends NodeInterface {
+        void execute(boolean value);
+
+        static SetShutdownFlagNode create() {
+            return RFFIFactory.getBaseRFFI().createSetShutdownFlagNode();
+        }
+    }
+
     /*
      * The RFFI implementation influences exactly what subclass of the above nodes is created. Each
      * implementation must therefore, implement these methods that are called by the associated
@@ -189,6 +198,8 @@ public interface BaseRFFI {
 
     GlobNode createGlobNode();
 
+    SetShutdownFlagNode createSetShutdownFlagNode();
+
     /*
      * Some functions are called from non-Truffle contexts, which requires a RootNode
      */
@@ -273,4 +284,27 @@ public interface BaseRFFI {
             return unameRootNode;
         }
     }
+
+    final class SetShutdownFlagRootNode extends RFFIRootNode<SetShutdownFlagNode> {
+        protected SetShutdownFlagRootNode() {
+            super(RFFIFactory.getBaseRFFI().createSetShutdownFlagNode());
+        }
+
+        private static SetShutdownFlagRootNode setShutdownFlagRootNode;
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            rffiNode.execute((boolean) args[0]);
+            return RNull.instance;
+        }
+
+        public static SetShutdownFlagRootNode create() {
+            if (setShutdownFlagRootNode == null) {
+                setShutdownFlagRootNode = new SetShutdownFlagRootNode();
+            }
+            return setShutdownFlagRootNode;
+        }
+    }
+
 }
-- 
GitLab