Re: [pcre-dev] PCRE2 and thread safety of jit compilation?

Top Page
Delete this message
Author: ph10
Date:  
To: Zoltán Herczeg
CC: Pcre
Subject: Re: [pcre-dev] PCRE2 and thread safety of jit compilation?
On Mon, 4 Jan 2016, Zoltán Herczeg wrote:

> the JIT compilation itself should be thread safe as before (no global
> variables are used for compilation).


There are no global variables, true, but the threads may be sharing the
block of data that represents a compiled pattern. The pcre2_match()
function decides whether or not to run a JIT match by looking at
re->executable_jit - and I see in the code that it gets set before
filling in other things:

  /* Reuse the function descriptor if possible. */
  if (re->executable_jit != NULL)
    functions = (executable_functions *)re->executable_jit;
  else
    {
    functions = SLJIT_MALLOC(sizeof(executable_functions), allocator_data);
    if (functions == NULL)
      {
      /* This case is highly unlikely since we just recently
      freed a lot of memory. Not impossible though. */
      sljit_free_code(executable_func);
      PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
      return PCRE2_ERROR_NOMEMORY;
      }
    memset(functions, 0, sizeof(executable_functions));
    functions->top_bracket = re->top_bracket + 1;
    functions->limit_match = re->limit_match;
    re->executable_jit = functions;
    }


  /* Turn mode into an index. */
  if (mode == PCRE2_JIT_COMPLETE)
    mode = 0;
  else
    mode = (mode == PCRE2_JIT_PARTIAL_SOFT) ? 1 : 2;


SLJIT_ASSERT(mode < JIT_NUMBER_OF_COMPILE_MODES);
functions->executable_funcs[mode] = executable_func;
functions->read_only_data_heads[mode] = common->read_only_data_head;
functions->executable_sizes[mode] = executable_size;
return 0;

Surely something will go wrong if another thread calls pcre2_match() or
pcre2_jit_match() on the same compiled pattern after re->executable_jit
has been set, but before the final statements that set functions->etc ?

> However, if the compilation is in progress, and the NULL has not been
> changed yet (kind of a racing condition), it starts another
> compilation. I think to avoid such situations is the application
> responsibility.


Indeed, this is another dangerous possibility - two threads deciding to
do a JIT compile at the same time. This is no different in principle
from a scenario where the patterns are not compiled initially, but each
thread decides to compile them as it needs them, while sharing the
compiled data with other threads. Your need an "I am compiling this
pattern, please wait" lock.

Philip

--
Philip Hazel