Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Fix cannot throw scoped exception #1799

Merged
merged 1 commit into from Apr 5, 2017
Merged

Conversation

WalterBright
Copy link
Member

because that would leak it and cause corruption.

@WalterBright
Copy link
Member Author

Blocking dlang/dmd#6675 which checks for this kind of bug.

@schveiguy
Copy link
Member

This is not a bug. The exception is caught inside the scope always. The idea is to avoid any gc activity. Is there a better way to do this?

@WalterBright
Copy link
Member Author

The exception is caught inside the scope always.

Yes, you are right. I missed that.

The idea is to avoid any gc activity. Is there a better way to do this?

Yes. Return an error code (by return value or an out parameter). All DeprecatedCycleException does is flag an error, it doesn't even have a message.

@WalterBright
Copy link
Member Author

Fixed it to use error code for cycles instead of exception.

@WalterBright WalterBright changed the title Fix Memory Corruption: cannot throw scoped exception Fix cannot throw scoped exception Apr 4, 2017
@WalterBright
Copy link
Member Author

@schveiguy you're the right person to review this

@schveiguy
Copy link
Member

I'll take a look. The convenience of the stack unwinding is what I liked about that mechanism.

Copy link
Member

@schveiguy schveiguy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, when I was developing this "fix" for the deprecated cycle detection, I tried doing what you are doing, and thought the exception mechanism is much cleaner and easier to implement.

Perhaps we should also re-examine whether the GC should be verboten at this stage. I'm wondering if we can just throw an allocated exception, and then delete it in the catch handler. From a philosophical standpoint, we're still using the GC when an actual cycle is detected, but if the program runs as planned, it is @nogc, even if a deprecated cycle is detected. But from a practical standpoint, if we allocate when throwing, and then delete within the catch, it would be pretty much equivalent. I'm not sure what the requirements are this early in the process, perhaps @MartinNowak has some more insight.

In any case, with the requested change, I think this will work.

src/rt/minfo.d Outdated
}
catch(DeprecatedCycleException)
bool cycle = false;
_ctors = doSort(MIctor | MIdtor, cycle);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to do this a weird way. The old algorithm sets _ctors and _tlsctors internally, so the assignment cannot happen. The exception prevented the assignment. You need to do something like this:

auto ctorTemp = doSort(MIctor | MIdtor, cycle);
if(!cycle)
{
    _ctors = ctorTemp;
    ctorTemp = doSort(MItlsctor | MItlsdtor, cycle);
    if(!cycle)
        _tlsctors = ctorTemp;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented the suggested behavior, but changed the return to a ref parameter which simplifies the logic.

In general, the GC should not be used in druntime if it can be avoided.

Exceptions are expensive (both to throw and in code size) and should be avoided where reasonable.

Copy link
Member

@schveiguy schveiguy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional improvement listed, but this would work as you have it.

}

immutable(ModuleInfo)*[] doSort(size_t relevantFlags)
// `cycle` is set to `true` if deprecated cycle error otherwise set `result`.
void doSort(size_t relevantFlags, ref bool cycle, ref immutable(ModuleInfo)*[] result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... what about returning bool, and then if statement below reads:

if (doSort(...) || doSort(...))

In any case, the new code is correct at least.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning both a bool and a ref with the same value strikes me as odd and a bit eyebrow raising. I'd need a better reason to use it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just get this merged and move on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean, you just would return a bool. But not important right now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, the ref parameter is no longer required if doSort just returns a bool.

@schveiguy
Copy link
Member

Auto-merge toggled on

@schveiguy schveiguy merged commit 68301f6 into dlang:master Apr 5, 2017
@WalterBright WalterBright deleted the minfo-scope branch April 5, 2017 01:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
3 participants