Is the RegExp object in VBScript Thread Safe when used inside a Windows Scripting Component

421 views Asked by At

I've trying to track down an issue with a legacy Windows Scripting Component that we use. Looking at several memory dumps in WinDbg I have found that alot of threads, in fact looks like 50% of the apps threads are all waiting for another thread to complete. This thread has a long stack which is below. This thread is doing some work with a RegExp object, so my question is now is RegExp thread safe?

It certainly looks like it isn't from all the other threads waiting on it but I want to be certain before I jump to conclusions and have struggled to find any real information online.

vbscript!RegExpExec::PopGreedyStar+3a    
vbscript!RegExpExec::FExecAux+639    
vbscript!RegExpExec::FExec+1f    
vbscript!RegExpExec::Exec+5a0    
vbscript!RegExpExec::ReplaceUsingString+2d    
vbscript!CRegExp::OrigReplace+14e    
vbscript!CRegExp::Replace+80    
oleaut32!DispCallFunc+16a    
oleaut32!CTypeInfo2::Invoke+234    
vbscript!CRegExp::Invoke+24    
vbscript!IDispatchInvoke2+b2    
vbscript!IDispatchInvoke+59    
vbscript!InvokeDispatch+13a    
vbscript!InvokeByName+42    
vbscript!CScriptRuntime::RunNoEH+22b2    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CScriptRuntime::RunNoEH+1e02    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CSession::Execute+c8    
vbscript!NameTbl::InvokeEx+516    
scrobj!DoInvoke+2c    
scrobj!NameTable::InvokeEx+e6    
scrobj!ComDispatchEx::InvokeEx+25    
scrobj!DoInvoke+2c    
scrobj!InvokeMember+a3    
scrobj!NameTable::InvokeEx+aa    
scrobj!ComDexHandler::Inner::InvokeEx+25    
vbscript!IDispatchExInvokeEx2+a9    
vbscript!IDispatchExInvokeEx+56    
vbscript!InvokeDispatch+101    
vbscript!InvokeByName+42    
vbscript!CScriptRuntime::RunNoEH+234c    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CScriptRuntime::RunNoEH+1bbd    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CSession::Execute+c8    
vbscript!NameTbl::InvokeEx+516    
vbscript!IDispatchExInvokeEx2+a9    
vbscript!IDispatchExInvokeEx+56    
vbscript!InvokeDispatch+101    
vbscript!InvokeByName+42    
vbscript!CScriptRuntime::RunNoEH+234c    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CScriptRuntime::RunNoEH+1bbd    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CScriptRuntime::RunNoEH+1bbd    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CScriptRuntime::RunNoEH+1bbd    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CSession::Execute+c8    
vbscript!NameTbl::InvokeEx+516    
vbscript!IDispatchExInvokeEx2+a9    
vbscript!IDispatchExInvokeEx+56    
vbscript!InvokeDispatch+101    
vbscript!InvokeByName+42    
vbscript!CScriptRuntime::RunNoEH+234c    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CScriptRuntime::RunNoEH+1beb    
vbscript!CScriptRuntime::Run+62    
vbscript!CScriptEntryPoint::Call+51    
vbscript!CSession::Execute+c8    
vbscript!COleScript::ExecutePendingScripts+144    
vbscript!COleScript::SetScriptState+14d 
1

There are 1 answers

0
Cheeso On

I don't know about thread safety in your case. But, looking at your situation, I'd say it's more likely to be a problem in the regex itself. That would be the first thing I would look at. It's possible to create a regex that itself causes a stack overflow, or a very very long runtime, because of quantifiers and re-starts.

From the pcre man page:

   When a pattern contains an unlimited repeat inside  a  subpattern  that
   can  itself  be  repeated  an  unlimited number of times, the use of an
   atomic group is the only way to avoid some  failing  matches  taking  a
   very long time indeed. The pattern

     (\D+|<\d+>)*[!?]

   matches  an  unlimited number of substrings that either consist of non-
   digits, or digits enclosed in <>, followed by either ! or  ?.  When  it
   matches, it runs quickly. However, if it is applied to

     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

   it  takes  a  long  time  before reporting failure. This is because the
   string can be divided between the internal \D+ repeat and the  external
   *  repeat  in  a  large  number of ways, and all have to be tried. (The
   example uses [!?] rather than a single character at  the  end,  because
   both  PCRE  and  Perl have an optimization that allows for fast failure
   when a single character is used. They remember the last single  charac-
   ter  that  is required for a match, and fail early if it is not present
   in the string.) 

Now, the RegExp object available in the Windows Script Host is not pcre, but I believe the same behavior would have to apply to it.

So, check your regex for nested unlimited quantifiers.