regex sets: fix Solaris optimiser bug
authorDavid Mitchell <davem@iabyn.com>
Sat, 12 Mar 2016 09:39:41 +0000 (09:39 +0000)
committerDavid Mitchell <davem@iabyn.com>
Sat, 12 Mar 2016 10:22:51 +0000 (10:22 +0000)
[perl #127455]

On Solaris with -DDEBUGGING, re/regex_sets.t was failing to compile.

This appears to be due to an optimiser bug.

The code in question looked like:

  handle_operand:
    top_index = av_tindex_nomg(stack);
    if (top_index - fence >= 0) {
        ...
    }

printf()ing the value of fence after the av_tindex_nomg() showed that its
value was corrupted (compared with its expected value based on a different
platform with the same debugging print). However, putting a another printf
prior to the av_tindex_nomg() call not only displayed the correct value,
but caused the later printf() to also display the correct value. It seems
that merely accessing fence prior to av_tindex_nomg() avoids the
corruption.

Simplifying the av_tindex_nomg(), the bad behaviour could be reduced to:

    if (!stack) { __assert( "" , "", 1); }

Putting a printf after this gave a corrupted fence; a printf before
made everything work.

So this workaround commit just makes sure that fence is accessed prior to
calling av_tindex_nomg().

regcomp.c

index ffee749..e1dc3c8 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -15122,7 +15122,22 @@ redo_curchar:
              * stack, we have to check if it is a !.  But first, the code above
              * may have altered the stack in the time since we earlier set
              * 'top_index'.  */
-            top_index = av_tindex_nomg(stack);
+
+            {
+                /* Work round an optimiser bug in Solaris Studio 12.3:
+                 * for some reason, the presence of the __assert() in
+                 * av_tindex_nomg() causes the value of fence to get
+                 * corrupted, even though the assert is never called. So
+                 * save the value then restore afterwards.
+                 * Note that in fact merely accessing the value of fence
+                 * prior to the statement containing the assert is enough
+                 * to make the bug go away.
+                 */
+                IV f = fence;
+                top_index = av_tindex_nomg(stack);
+                fence = f;
+            }
+
             if (top_index - fence >= 0) {
                 /* If the top entry on the stack is an operator, it had better
                  * be a '!', otherwise the entry below the top operand should