Skip to content

[lldb] Find public Objective-C class when reconstructing type #3188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

augusto2112
Copy link

When reconstructing a private Objective-C type, walk up the
type hierarchy until a type importable from Swift is found or
until we run out of types.

Copy link

@adrian-prantl adrian-prantl left a comment

Choose a reason for hiding this comment

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

LGTM, some nitpicks inside :-)

@@ -4401,6 +4406,33 @@ swift::TypeBase *SwiftASTContext::ReconstructType(ConstString mangled_typename,
*ast_ctx, mangled_typename.GetStringRef())
.getPointer();

// If we couldn't find the type and it's an obj-c type,
// walk up the type hierarchy until we find something we can
// import, or until we run out of types.

Choose a reason for hiding this comment

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

This comment explains what the code does, but not why. How about:

Objective-C classes sometimes have private subclasses that are invisible to the Swift compiler because they are declared and defined in a .m file. If we can't reconstruct an ObjC type, walk up the type hierarchy until we find something we can import, or until we run out of types.

// walk up the type hierarchy until we find something we can
// import, or until we run out of types.
while (!found_type) {
auto clang_type = GetAsClangType(mangled_typename);

Choose a reason for hiding this comment

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

CompilerType clang_type
GetAsClangType doesn't really have an obvious return type

auto *super_interface_decl = interface_decl->getSuperClass();
if (!super_interface_decl)
break;
auto super_type = clang_ctx->GetTypeForDecl(super_interface_decl);

Choose a reason for hiding this comment

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

here the type also isn't obvious from the name

When reconstructing a private Objective-C type, walk up the
type hierarchy until a type importable from Swift is found or
until we run out of types.
@augusto2112 augusto2112 force-pushed the reconstruct-type-hierarchy branch from d326052 to 33bf8f7 Compare August 23, 2021 16:28
@augusto2112 augusto2112 merged commit 57f3bfc into swiftlang:stable/20210726 Aug 23, 2021
@dreampiggy
Copy link

dreampiggy commented May 11, 2022

Hi there. Sorry to bother again. @adrian-prantl @augusto2112 🤦‍♂️

Recently we found, when user disable the TypeRef mirror impl of Swift symbol resolve, this will cause an infinity loop and finally crash.

Reproduce demo

The crash happens for those private Objc type who is not visiable to compiler. Like Apple's private type UICTFont in UIKitCore, (returned from UIFont.systemFont(ofSize:) public API)

  • Use Xcode 13.3 Create New iOS Demo
  • Add these code into ViewController.swift's viewDidLoad
var font: UIFont = UIFont.systemFont(ofSize: UIFont.systemFontSize)
print("break here")
  • Add this line into ~/.lldbinit
symbols.use-swift-typeref-typesystem false
  • Set breakpoint at that print line
  • Run and see the crash

截屏2022-05-11 下午8 23 11

Crash Log:

lldb-rpc-server_2022-05-11-172619_lizhuolideMacBook-Pro.txt

Reason

I found that, during this PR: #3204
which introduce the new way, to use ObjcRuntime to dynamic resolve the class, and import into SwiftTypeRefTypeSystem via RemangleAsType. Here, for my example, UICTFont, which mangled as $sSo8UICTFontCD.

However, since the type is private type, it's not visible for compiler and no debug info about that. So, when fallback on SwiftASTContext for symbol discovery. The SwiftASTContext::ReconstructType("$sSo8UICTFontCD") will start to infinity loop call, because it can never get what of that $sSo8UICTFontCD is, and finally cause stack overflow.

The infinity call order

  1. ast_ctx.GetAsClangType("$sSo8UICTFontCD")
  2. ts->IsImportedType("$sSo8UICTFontCD")
  3. ts->ReconstructType("$sSo8UICTFontCD")
  4. ast_ctx.ReconstructType("$sSo8UICTFontCD")
  5. ast_ctx.GetAsClangType("$sSo8UICTFontCD")

image

Solution ?

I'm not really familiar with the changes. Here is our temp patch:

patch.diff.txt

Which use the TypeSystemClang for return instead of any SwiftTypeSystem. Because I think that CompilerType::GetTypeName will still call that SwiftASTContext::ReconstuctType, and result the same issue.

image

@augusto2112
Copy link
Author

@dreampiggy thank you for the detailed report! I'll take a look at the issue.

@augusto2112
Copy link
Author

@dreampiggy, I'm curious, why do you need to disable the typeref typesystem?

@dreampiggy
Copy link

dreampiggy commented May 13, 2022

Actually it's because of debugging performance and experience. :(

For our internal company's large iOS project, which use heavily of Swift source code (more than 400+ Swift Module, 100K+ Lines souce), and mixing of Objc/C/C++/Rust code and binary.

We found the huge performance regression when using the default symbols.use-swift-typeref-typesystem true. The simple po self and frame variable command on some Swift Module will lag for 40 seconds+. (We have already use some other improvements about clang extra module discovery and something, I may submit to Apple or LLVM lately)

When using symbols.use-swift-typeref-typesystem false, the po self and frame variable command on the same Swift Module will only lag for 10 seconds.

This is why we disable that option, for now.

To be honest, if the typeref mirror implementation can get a better debugging performance or at least equal to the old SwiftASTContext one, we will use the default option as usual.


Here is one Demo which I previously provided to adrian for another issue. Which looks a little similiar to our internal project issue: https://github.com/PRESIDENT810/slowDebugTest/tree/simulate_massive_module (simulate_massive_module branch)

@augusto2112
Copy link
Author

@dreampiggy thank you for the feedback!

@adrian-prantl
Copy link

We found the huge performance regression when using the default symbols.use-swift-typeref-typesystem true. The simple po self and frame variable command on some Swift Module will lag for 40 seconds+. (We have already use some other improvements about clang extra module discovery and something, I may submit to Apple or LLVM lately)

Do you think you could share a trace of lldb-rpc-server captured with xcrun xctrace record --output ~/Desktop --template "Time Profiler" --attach lldb-rpc-server --window 5m during those 40s? Since it's a huge file you could attach it to Feedback Assistant.

@dreampiggy
Copy link

Hi. I'll try to collect and profile and submit for you weekend, with the radar ID or some thirdparty CDN url.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants