Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

MSVC/x86 exception handling: rewrite avoiding VC runtime internals #54

Closed
wants to merge 4 commits into from

Conversation

rainers
Copy link

@rainers rainers commented Jan 22, 2016

  • setup exception handler for exceptions during cleanup to avoid C++ calling std::terminate
  • remove vcruntime hacks
  • when converting exception to error, do not rethrow if the catch handles errors, too
  • add support for the "safeseh" attribute

}

extern(C) void _d_leave_cleanup(void* ptr)
// @safeseh to be marked as "safe" for the OS securtity check
Copy link
Member

Choose a reason for hiding this comment

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

securtity => security

@JohanEngelen
Copy link
Member

@rainers
Copy link
Author

rainers commented Jan 26, 2016

Could you also make an IR testcase for this? ;-)

I'll try though I've yet to see any of the IR tests to pass on my system.
Do you think adding an attribute for safeseh is the right direction? It could also be buried in the target-specific attributes, as it is very specific to Win32.

@rainers
Copy link
Author

rainers commented Jan 26, 2016

securtity => security
void * => void* etc. pls, for consistency, also for function below

Done.

@JohanEngelen
Copy link
Member

I'll try though I've yet to see any of the IR tests to pass on my system.
Really? Not to hijack this thread: can you open a new issue for it with some details of error messages?

@rainers
Copy link
Author

rainers commented Jan 27, 2016

Really? Not to hijack this thread: can you open a new issue for it with some details of error messages?

Sorry for being slow with this, I've just reported it here: ldc-developers/ldc#1265

@rainers
Copy link
Author

rainers commented Jan 28, 2016

Finally implemented swapping exception information for fibers and figured why exceptions where never caught in fibers.
With this change, core.thread also passes its unittests in debug and release builds.

@rainers
Copy link
Author

rainers commented Jan 29, 2016

I've added support for catching D exceptions in C++, see ldc-developers/dmd-testsuite#15 for a demonstrating test case.

@@ -4854,16 +4858,21 @@ private:
finalHandler = reg.handler;
}

pstack -= EXCEPTION_REGISTRATION.sizeof;
// With safeseh(?), the chain must not extend to the very top
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the explanation and the change, it's a lot clearer to me now. (I thought you were referring to the beginning of the record before instead of to the past-the-end address.)

Shouldn't the change also go into the upstream implementation, though? (We can just cherry-pick the fix from master afterwards.)

Copy link
Author

Choose a reason for hiding this comment

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

Shouldn't the change also go into the upstream implementation, though? (We can just cherry-pick the fix from master afterwards.)

I don't think dmd will ever support safeseh. It shouldn't do harm to add it, though.

Copy link
Author

Choose a reason for hiding this comment

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

@rainers
Copy link
Author

rainers commented Jan 30, 2016

Updated to allow any exception type to be mapped to C++.
I also applied some of the ideas from rainers#4

{
auto olength = other._length; other._length = _length; _length = olength;
auto op = other._p; other._p = _p; _p = op;
auto ocap = other._cap; other._cap = _cap; _cap = ocap;
Copy link
Member

Choose a reason for hiding this comment

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

Just nit-picking, but how about:

static void swapField(T)(ref T a, ref T b) { T o = b; b = a; a = o; }
swapField(_length, other._length);
swapField(_p,      other._p);
swapField(_cap,    other._cap);

Copy link
Author

Choose a reason for hiding this comment

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

Done. I think there should be a swap function somewhere in druntime, it is implemented again and again...

@kinke
Copy link
Member

kinke commented Jan 31, 2016

I've cherry-picked your upstream commit regarding core.thread, so another rebase is needed. While at it, could you please squash the last 4 commits to a single one and then factor out the C++ stuff (2nd mangling, _d_toString()) in a separate commit again?

@rainers
Copy link
Author

rainers commented Jan 31, 2016

Rebased and squashed some commits.

There's still one open issue that doesn't work with this design: cleanup funclets cannot have exception handling themselves, but that's valid in D, e.g. by using try/catch in scope(exit). The LLVM devs don't plan to implement this any time soon.

That's why I want to try outlining cleanup code in the front-end. This might also help the x64 implementation, as it is unlikely that you can setup exception information on x64 as done here (emplace an exception frame in the calling functions stack space).

@kinke
Copy link
Member

kinke commented Jan 31, 2016

Rebased and squashed some commits.

👍

That's why I want to try outlining cleanup code in the front-end. This might also help the x64 implementation, as it is unlikely that you can setup exception information on x64 as done here (emplace an exception frame in the calling functions stack space).

And I thought it'd be finished. ;) All the best for your next adventure then, you rock! :)

@rainers
Copy link
Author

rainers commented Feb 1, 2016

Not sure it'll work out this time. I expect some troubles regarding cleanups that are already inside nested functions.
So maybe it's better to get this in as an (almost) working solution for x86...

@kinke
Copy link
Member

kinke commented Feb 2, 2016

It is unlikely that you can setup exception information on x64 as done here

Do you think the current method (setting up the std::terminate hook) is going to be the (first) x64 solution? That's the reason I haven't merged this yet... ;)

@rainers
Copy link
Author

rainers commented Feb 5, 2016

Do you think the current method (setting up the std::terminate hook) is going to be the (first) x64 solution? That's the reason I haven't merged this yet... ;)

I hope I can try the frontend-outling this weekend. If that doesn't work out, merging the two solutions might be the best solution ATM for x64 support.

@rainers
Copy link
Author

rainers commented Feb 9, 2016

I hope I can try the frontend-outling this weekend.

FYI: I actually managed to rewrite cleanup blocks, e.g. finally { code } to finally { _d_cleanup(() { code }); }, with _d_cleanup just calling the delegate, but replacing the function for unwind cleanups with another that catches exceptions.

Unfortunately, it causes some of the expected compile errors when having to access several contexts. In addition, errors show the additional indirection in instantiation traces (_d_cleanup must be a template to inherit function attributes). So it doesn't seem a good solution ATM.

I'm currently torn between this and the previous version using the std::terminate hook. Both are rather hacky. I'll investigate how to make the latter safer to avoid skipping a std::terminate call that's not initiated by an exception during cleanup (it would probably also crash).

@rainers
Copy link
Author

rainers commented Mar 1, 2016

Closing this in favor of #60.

@rainers rainers closed this Mar 1, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants