tablacus / TablacusScriptControl

Script Control for 64-bit platforms
https://tablacus.github.io/scriptcontrol_en.html
MIT License
62 stars 17 forks source link

fix unhandled exception (empty arguments and uninitialized m_pEI) #29

Closed ghuDaYuYu closed 2 years ago

ghuDaYuYu commented 2 years ago

First of all thank you so much for providing this library! I pull this request to share fixes that seam to have solved two issues I encountered.

app. c++

IScriptControlPtr script_control;
_com_util::CheckError(script_control.CreateInstance(__uuidof(ScriptControl)));

try {

    BSTR bsLang = ::SysAllocString(L"JScript");
    script_control->put_Language(bsLang);
    ::SysFreeString(bsLang);

    BSTR bsScript = ::SysAllocString(L"function badSyntax() return new Array(0, 1, 2);}");
    script_control->AddCode(bsScript);
    ::SysFreeString(bsScript);

} catch (_com_error& e) {

      ::SysFreeString(bsScript);
      rethrow_error(e);
}

The missing bracket in the script triggered either an unhandled exception in jscript.dll or AV exceptions.

Initializing m_pEI inside the CTScriptControl constructor seams to solve it:

CTScriptControl::CTScriptControl()
{
    ITypeLib *pTypeLib;
    m_pEI = NULL;

    ...
}

... as this if statement no longer evaluates to true (CTScriptControl::Invoke never runs in my use case?).

STDMETHODIMP CteActiveScriptSite::OnScriptError(IActiveScriptError *pscripterror)
{
    ...

    if (m_pSC->m_pEI) {
        try {
            if SUCCEEDED(pscripterror->GetExceptionInfo(m_pSC->m_pEI)) {
                m_pSC->m_hr = DISP_E_EXCEPTION;
            }
        }
        catch (...) {
            m_pSC->m_hr = DISP_E_EXCEPTION;
        }
    }
    ...
}

Not sure if this fix may affect other functions like:

HRESULT CTScriptControl::SetScriptError(int n)

Also I have seen that this pull request is related to m_pEI.

app. c++

BSTR bsScript = ::SysAllocString(L"function eyePos() { return new Array(0, 1, 2);   }");
script_control->AddCode(bsScript);
::SysFreeString(bsScript);

...
//lenght is 0 for no arguments
ULONG length = sizeof...(_Args);
CComSafeArray<VARIANT> params{length};

try {
      return Ret(m_script_control->Run(uT(func), params.GetSafeArrayPtr()));
} catch (_com_error& e) {
     if (e.Error() == DISP_E_UNKNOWNNAME) {
       throw script_error(
           PFC_string_formatter() << "Error: Function " << func << "() not found.");
     } else {
        rethrow_error(e);
     }
}

The code runs in 32bit mode but crashes on 64bit.

Issue was solved at first by adding a dummy argument to the parameters, then applied the following modification:

(nArg is set to -1 for empty parameter list)

STDMETHODIMP CTScriptControl::raw_Run(BSTR ProcedureName, SAFEARRAY ** Parameters, VARIANT *pvarResult)
{
    ...
    if (*Parameters) {
        ::SafeArrayGetUBound(*Parameters, 1, &nArg);
        nArg++;
        if (nArg > 0) {
            pv2 = GetNewVARIANT(nArg);
            ...
        }
    }
    ...
}

That´s it... thanks again for the great job!

I'll be grateful if you find the time to review this pull request,

Best regards