www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 21013] New: dwarfeh: Comparing LSDA is too unreliable to

https://issues.dlang.org/show_bug.cgi?id=21013

          Issue ID: 21013
           Summary: dwarfeh: Comparing LSDA is too unreliable to determine
                    if two exceptions can be merged
           Product: D
           Version: D2
          Hardware: All
                OS: Linux
            Status: NEW
          Severity: major
          Priority: P1
         Component: druntime
          Assignee: nobody puremagic.com
          Reporter: ibuclaw gdcproject.org

The run-time implementation of D EH personality routines tries to cater for
merging two in-flight exceptions.  In order to do this for Dwarf/Unwind EH, it
assumes that each function will have only one LSDA, and it will be unique to
that function.

See [1] for combining two in-flight exceptions before switching to the handler,
and [2] for determining which of the in-flight Exceptions takes precedence when
search for a catch/finally handler.

[1]
https://github.com/dlang/druntime/blob/d3dfa0778fbad77482b0ae8e7e528b55aa417c19/src/rt/dwarfeh.d#L413-L418
[2]
https://github.com/dlang/druntime/blob/d3dfa0778fbad77482b0ae8e7e528b55aa417c19/src/rt/dwarfeh.d#L479-L485

--------------------------------------------------------

Line [1] Breaks if the function is partitioned into two.

e.g:
---
void bug1513a()
{
     throw new Exception("d");
}

void bug1513()
{
    try
    {
        try
        {
            bug1513a();
        }
        finally
        {
           throw new Exception("f");
        }
    }
    catch(Exception e)
    {
        assert(e.msg == "d");       // <-- Assertion failure here
        assert(e.next.msg == "f");
        assert(!e.next.next);
    }
}
---

No combining happens because there are two LSDA's for bug1513().
---
_D4test7bug1513FZv:
  push    rbp
  mov     rbp, rsp
  call    _D4test8bug1513aFZv
  jmp     .L5
//
// LSDA for bug1513()
//
_D4test7bug1513FZv.cold:
.L5:
        ...
//
// LSDA for bug1513.cold()
//
---

--------------------------------------------------------

Line [2] breaks if one function is inlined into another.

e.g:
---
void test4()
{
    void throw_catch()
    {
        try
        {
            throw new MyException;
        }
        catch (MyException)
        {
        }
        catch (Exception)
        {
            assert(false);      // <-- Assertion failure here
        }
    }
    try
    {
        try
        {
            throw new Exception("a");
        }
        finally
        {
            throw_catch();
        }
    }
    catch(Exception e)
    {
        assert(e.msg == "a");
        assert(!e.next);
    }
}
---

The function throw_catch() is inlined into its parent, and so both now share
the same LSDA.  This means that the catch handler for MyException is now
ignored because there's already an in-flight Exception that takes precedence
because they appear to be thrown from the same function.

--
Jul 05 2020