This is an archive of the discontinued LLVM Phabricator instance.

Prevent infinite recursive loop in AppleObjCTrampolineHandler constructor
ClosedPublic

Authored by fjricci on Jan 7 2016, 3:48 PM.

Details

Summary

When we construct AppleObjCTrampolineHandler, if m_impl_fn_addr is invalid, we call CanJIT(). If the gdb remote process does not support allocating and deallocating memory, this call stack will include a call to the AppleObjCRuntime constructor. The AppleObjCRuntime constructor will then call the AppleObjCTrampolineHandler constructor, creating a recursive call loop that eventually overflows the stack and segfaults.

Avoid this call loop by not constructing the AppleObjCTrampolineHandler within AppleObjCRuntime until we actually need to use it.

Diff Detail

Event Timeline

fjricci updated this revision to Diff 44279.Jan 7 2016, 3:48 PM
fjricci retitled this revision from to Prevent infinite recursive loop in AppleObjCTrampolineHandler constructor.
fjricci updated this object.
fjricci added reviewers: clayborg, jingham.
fjricci added subscribers: lldb-commits, sas.
jingham edited edge metadata.Jan 7 2016, 4:11 PM

Can you post the backtrace in this case? It seems to me odd that CanJIT -> AllocateMemory needs to construct the AppleObjCRuntime to do its job. I'd rather cut the chain at that point if it makes sense.

fjricci added a comment.EditedJan 7 2016, 5:41 PM

Here's a paste of the end of the backtrace.

pastebin.com/3VkF3Biq

Ah, right. We're doing that so that we can make sure that an ObjC Exception thrown during the course of expression evaluation doesn't unwind past the frame we are using to call the function.

Seems like for low-level stuff like AllocateMemory we should be avoiding all this extra work, which you can do by calling options.SetTrapExceptions(false) on the ExpressionEvaluationOptions that you pass in to the thread plan in InferiorCallMmap in InferiorCallPOSIX.cpp.

Would you mind checking that adding that bit to InferiorCallMmap (without your change to avoid recursion fixes the problem as well.) I don't mind the current change as well, but it would be really nice to get the ObjC runtime out of the picture when trying to allocate memory...

That penultimate sentence would be clearer if I had put the end ")" in the right place - after "recursion"

fjricci updated this revision to Diff 44305.Jan 7 2016, 6:59 PM
fjricci edited edge metadata.

Follow suggestion by @jingham to avoid setting up ObjC runtime for low-level POSIX memory allocations

@jingham - your suggestion does avoid the recursion as well, and seems a lot cleaner.

Cool! For completeness I think it is a good idea to do this to all the functions in InferiorCallPOSIX. For the general InferiorCall one it might be a good idea to add a defaulted (to false) parameter so that if somebody really needs to use it for something that might throw they can. But this is for calling simple low level function which shouldn't be throwing, so defaulting to not firing up the runtimes to catch exceptions is more appropriate.

Then this is good to go.

clayborg accepted this revision.Jan 8 2016, 9:36 AM
clayborg edited edge metadata.
This revision is now accepted and ready to land.Jan 8 2016, 9:36 AM

Would you still like me to make the parameter change to InferiorCallMmap before merging?

If you don't mind, please add the same code to the InferiorCallMunmap, and then add the same thing to InferiorCall, but that's the one that should take a parameter in case somebody does end up using the general function for something that could throw. Otherwise we'll just end up coming back to this again later...

Sounds good, will do.

fjricci updated this revision to Diff 44361.Jan 8 2016, 12:27 PM
fjricci edited edge metadata.

Disable exception trapping by default on all functions in InferiorCallPOSIX

jingham accepted this revision.Jan 8 2016, 12:29 PM
jingham edited edge metadata.

Great, thanks!

sas closed this revision.Jan 8 2016, 12:36 PM

Committed as r257204.