Browse Source

HPCC-21633 ECLAgent may crash at termination after using Java embeds

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 6 years ago
parent
commit
413a410a54

+ 4 - 0
ecl/hql/hqlatoms.cpp

@@ -65,6 +65,7 @@ IIdAtom * precompileId;
 IIdAtom * __queryId;
 IIdAtom * selfId;
 IIdAtom * sharedId;
+IIdAtom * singletonEmbedContextId;
 IIdAtom * storeId;
 IIdAtom * substituteEmbeddedScriptId;
 IIdAtom * supportsImportId;
@@ -421,6 +422,7 @@ IAtom * httpHeaderAtom;
 IAtom * prototypeAtom;
 IAtom * proxyAddressAtom;
 IAtom * sampleAtom;
+IAtom *_singletonEmbedContext_Atom;
 IAtom * sort_AllAtom;
 IAtom * sort_KeyedAtom;
 IAtom * sortedAtom;
@@ -538,6 +540,7 @@ MODULE_INIT(INIT_PRIORITY_HQLATOM)
     MAKEID(__query);
     MAKEID(self);
     MAKEID(shared);
+    MAKEID(singletonEmbedContext);
     MAKEID(store);
     MAKEID(substituteEmbeddedScript);
     MAKEID(supportsImport);
@@ -883,6 +886,7 @@ MODULE_INIT(INIT_PRIORITY_HQLATOM)
     MAKEATOM(serialization);
     MAKEATOM(set);
     MAKEATOM(shared);
+    MAKESYSATOM(singletonEmbedContext);
     MAKEATOM(shutdown);
     MAKESYSATOM(sideEffect);
     MAKEATOM(single);

+ 2 - 0
ecl/hql/hqlatoms.hpp

@@ -67,6 +67,7 @@ extern HQL_API IIdAtom * precompileId;
 extern HQL_API IIdAtom * __queryId;
 extern HQL_API IIdAtom * selfId;
 extern HQL_API IIdAtom * sharedId;
+extern HQL_API IIdAtom * singletonEmbedContextId;
 extern HQL_API IIdAtom * storeId;
 extern HQL_API IIdAtom * substituteEmbeddedScriptId;
 extern HQL_API IIdAtom * supportsImportId;
@@ -425,6 +426,7 @@ extern HQL_API IAtom * httpHeaderAtom;
 extern HQL_API IAtom * prototypeAtom;
 extern HQL_API IAtom * proxyAddressAtom;
 extern HQL_API IAtom * sampleAtom;
+extern HQL_API IAtom *_singletonEmbedContext_Atom;
 extern HQL_API IAtom * sort_AllAtom;
 extern HQL_API IAtom * sort_KeyedAtom;
 extern HQL_API IAtom * sortedAtom;

+ 6 - 2
ecl/hql/hqlfold.cpp

@@ -1662,8 +1662,12 @@ IHqlExpression * foldEmbeddedCall(IHqlExpression* expr, unsigned foldOptions, IT
     Owned<IValue> plugin = foldExternalCall(langLoadCall, foldOptions, templateContext);
     if (plugin == nullptr)
         return NULL;
-
-    Owned<IEmbedContext> __plugin = (IEmbedContext *) plugin->getIntValue();  // We declared as int since ecl has no pointer type - not sure what the clean fix is here...
+    // Slightly odd code - the getEmbedContext function returns a linked object or a singleton depending on a flag
+    bool singletonEmbedContext = body->hasAttribute(_singletonEmbedContext_Atom);
+    Owned<IEmbedContext> __pluginLinked;
+    IEmbedContext *__plugin = (IEmbedContext *) plugin->getIntValue();  // We declared as int since ecl has no pointer type - not sure what the clean fix is here...
+    if (!singletonEmbedContext)
+        __pluginLinked.setown(__plugin);  // Make sure we release it, if it's not a singleton
     DummyContext dummyContext;
     Owned<IEmbedFunctionContext> __ctx = __plugin->createFunctionContextEx(&dummyContext,nullptr,flags,optionsStr.str());
     EmbedContextBlock b(__ctx);

+ 3 - 0
ecl/hql/hqlgram2.cpp

@@ -946,6 +946,9 @@ IHqlExpression * HqlGram::processEmbedBody(const attribute & errpos, IHqlExpress
         OwnedHqlExpr threadlocal = pluginScope->lookupSymbol(threadlocalId, LSFpublic, lookupCtx);
         if (matchesBoolean(threadlocal, true))
             args.append(*createAttribute(_threadlocal_Atom));
+        OwnedHqlExpr singletonEmbedContext = pluginScope->lookupSymbol(singletonEmbedContextId, LSFpublic, lookupCtx);
+        if (matchesBoolean(singletonEmbedContext, true))
+            args.append(*createAttribute(_singletonEmbedContext_Atom));
         OwnedHqlExpr syntaxCheckFunc = pluginScope->lookupSymbol(isImport ? checkImportId : syntaxCheckId, LSFpublic, lookupCtx);
         OwnedHqlExpr precompile = isImport ? nullptr : pluginScope->lookupSymbol(precompileId, LSFpublic, lookupCtx);
         if (syntaxCheckFunc || precompile)

+ 1 - 1
ecl/hql/hqlutil.hpp

@@ -281,7 +281,7 @@ inline bool isInternalEmbedAttr(IAtom *name)
 {
     return name == languageAtom || name == projectedAtom || name == streamedAtom || name == _linkCounted_Atom || 
            name == importAtom || name==foldAtom || name==timeAtom || name==_prebind_Atom || name==_precompile_Atom || name==_original_Atom ||
-           name == _threadlocal_Atom || name == activityAtom || name == localAtom || name == parallelAtom;
+           name == _threadlocal_Atom || name == _singletonEmbedContext_Atom || name == activityAtom || name == localAtom || name == parallelAtom;
 }
 
 

+ 13 - 1
ecl/hqlcpp/hqlcpp.cpp

@@ -12065,9 +12065,21 @@ void HqlCppTranslator::buildScriptFunctionDefinition(BuildCtx &ctx, IHqlExpressi
     IValue *optionVal = embedOptions->queryValue();
 
     bool threadlocal = bodyCode->hasAttribute(_threadlocal_Atom) && queryVal != nullptr && optionVal != nullptr;
+    bool singletonEmbedContext = bodyCode->hasAttribute(_singletonEmbedContext_Atom);
     HqlExprArray noargs;
     OwnedHqlExpr getPlugin = bindFunctionCall(language, noargs);
-    OwnedHqlExpr pluginPtr = createQuoted(threadlocal ? "static thread_local Owned<IEmbedContext> __plugin" : "Owned<IEmbedContext> __plugin", getPlugin->getType());
+    OwnedHqlExpr pluginPtr;
+    const char *pluginPtrDef = nullptr;
+    if (threadlocal)
+    {
+        assertex(singletonEmbedContext);
+        pluginPtrDef = "static thread_local IEmbedContext *__plugin";
+    }
+    else if (singletonEmbedContext)
+        pluginPtrDef = "IEmbedContext *__plugin";
+    else
+        pluginPtrDef = "Owned<IEmbedContext> __plugin";
+    pluginPtr.setown(createQuoted(pluginPtrDef, getPlugin->getType()));
     buildAssignToTemp(funcctx, pluginPtr, getPlugin);
 
     StringBuffer createParam;

+ 4 - 3
plugins/javaembed/java.ecllib

@@ -16,15 +16,16 @@
 ############################################################################## */
 
 EXPORT Language := SERVICE : plugin('javaembed')
-  integer getEmbedContext():cpp,pure,namespace='javaembed',entrypoint='getEmbedContext',prototype='IEmbedContext* getEmbedContext()',fold;
+  integer queryEmbedContext():cpp,pure,namespace='javaembed',entrypoint='queryEmbedContext',prototype='IEmbedContext* queryEmbedContext()',fold;
   DATA precompile(const varstring funcname, UTF8 body, const varstring argnames, const varstring compileOptions, const varstring persistOptions):cpp,pure,namespace='javaembed',entrypoint='precompile',fold;
   STRING syntaxCheck(const varstring funcname, UTF8 body, const varstring argnames, const varstring compileOptions, const varstring persistOptions):cpp,pure,namespace='javaembed',entrypoint='syntaxCheck',fold;
   STRING checkImport(const varstring funcname, UTF8 importString, const varstring argnames, const varstring compileOptions, const varstring persistOptions):cpp,pure,namespace='javaembed',entrypoint='checkImport',fold;
 END;
-EXPORT getEmbedContext := Language.getEmbedContext;
+EXPORT getEmbedContext := Language.queryEmbedContext;
 EXPORT precompile := Language.precompile;
 EXPORT syntaxCheck := Language.syntaxCheck;
 EXPORT checkImport := Language.checkImport;
 EXPORT boolean supportsImport := true;
 EXPORT boolean supportsScript := true;
-EXPORT boolean threadlocal := true;
+EXPORT boolean threadlocal := true;
+EXPORT boolean singletonEmbedContext := true;

+ 7 - 0
plugins/javaembed/javaembed.cpp

@@ -4425,6 +4425,13 @@ public:
     }
 };
 
+static JavaEmbedContext embedContext;
+
+extern DECL_EXPORT IEmbedContext* queryEmbedContext()
+{
+    return &embedContext;
+}
+
 extern DECL_EXPORT IEmbedContext* getEmbedContext()
 {
     return new JavaEmbedContext;