[Mono-bugs] [Bug 609023] New: Interlocked.Exchange(ref int, int) raises a "System.ExecutionEngineException: SIGILL" exception on a S390X platform

bugzilla_noreply at novell.com bugzilla_noreply at novell.com
Wed May 26 08:33:02 EDT 2010


http://bugzilla.novell.com/show_bug.cgi?id=609023

http://bugzilla.novell.com/show_bug.cgi?id=609023#c0


           Summary: Interlocked.Exchange(ref int, int) raises a
                    "System.ExecutionEngineException: SIGILL" exception on
                    a S390X platform
    Classification: Mono
           Product: Mono: Runtime
           Version: SVN
          Platform: S/390-64
        OS/Version: SLES 10
            Status: NEW
          Severity: Major
          Priority: P5 - None
         Component: JIT
        AssignedTo: lupus at novell.com
        ReportedBy: aurelien.minvielle+mono at gmail.com
         QAContact: mono-bugs at lists.ximian.com
          Found By: ---
           Blocker: ---


Created an attachment (id=364865)
 --> (http://bugzilla.novell.com/attachment.cgi?id=364865)
Suggested patch, result from the "svn diff" command

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.2.3)
Gecko/20100423 Ubuntu/10.04 (CK-IBM) (CK-IBM) Firefox/3.6.3

Using the Interlocked.Exchange(ref int, int) method on a S390X hadware platfrom
raises a SIGILL exception.

The bug only appears with the Exchange(ref int, int) overload. For instance,
Exchange(ref long, long) works fine.

The following instructions trigger the bug :

int foo = 10;
Interlocked.Exchange(ref foo, 5); // raise the SIGILL exception

Reproducible: Always

Steps to Reproduce:
Here is a trivial test case that triggers the bug :

using System;
using System.Threading;

namespace Test
{
    class MainClass
    {   
        public static void Main (string[] args)
        {
            int foo = 10;
            Interlocked.Exchange(ref foo, 5);
        }
    }
}
Actual Results:  
Unhandled Exception: System.ExecutionEngineException: SIGILL
at Test.MainClass.Main (System.String[] args) [0x00002] in
/root/InterlockedTest.cs:11 

Expected Results:  
foo should equal 5 at the terminaison and no exception should be raised.

The problem is in the JIT compiler. The Interlocked.Exchange method has been
inlined. Here is the interesting part of the S390x assembly code generated at
runtime (from "mono -v -v") :

0000000000000000 <t_MainClass_Main>:
..
24:    a7 09 00 0a           lghi    %r0,10
28:    e3 00 f0 a8 00 50     sty    %r0,168(%r15) // initialize foo to 10
2e:    b9 04 00 2f           lgr    %r2,%r15    // copy frame base address
32:    a7 2b 00 a8           aghi    %r2,168     // calculate address of foo
36:    a7 39 00 05           lghi    %r3,5       // load new value (5)
3a:    e3 00 20 00 00 04     lg    %r0,0(%r2)  // load current value of foo
40:    ba 03 20 00           cs    %r0,%r3,0(%r2)    // compare r0 with foo and
store 5 if equal
44:    a7 74 ff fc           jne    3c <t_MainClass_Main+0x3c>


First remark : the variable foo is stored as a 64bit integer. That's a bit
strange, 32bits would be enough, and according to the .NET specification, "int"
should be mapped to "Int32". But let's assume this is wanted (perhaps 64bits
instructions are faster ?)

There are at least two mistakes in this generated assembly code.
The 32bits CS instruction is used instead of the 64bits CSG instruction, thus
comparing the high-order of the storage operand with the low-order of the
register r0. So the comparison with any non-zero value will fail.
The "JNE" jump is then performed. But its offset is obviously wrong : it lands
right in the middle of the LG instruction. It should jump at
t_MainClass_Main+0x3a instead of t_MainClass_Main+0x3c.

This assembly is generated by the following piece of code in
mono/mini/mini-s390x.c: :

case OP_ATOMIC_EXCHANGE_I4: {
    s390_lg  (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset);
    s390_cs  (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset);
    s390_jnz(code,-4);
    s390_lgfr(code, ins->dreg, s390_r0);
}

I suggest to replace the s390_cs call by s390_csg, and correct the s390_jnz
offset.
With a CS instruction, the JNZ offset should have been -5, not -4. With a CSG
instruction, It should now be -6.

This would add two half-words to the generated assembly for the
OP_ATOMIC_EXCHANGE_I4 opcode. The "len" specified for this opcode in
cpu-s390x:58 must be extended from 18 to 20.

These corrections seemed to do the trick for me. But perhaps the problem is
deeper : is this 64bits context correct ? Shouldn't the variable "int foo" be
stored as a 32bits integer ?

-- 
Configure bugmail: http://bugzilla.novell.com/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.


More information about the mono-bugs mailing list