Skip to content
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

[SR-10313] Segmentation Fault while using @dynamicCallable #52713

Closed
swift-ci opened this issue Apr 4, 2019 · 3 comments
Closed

[SR-10313] Segmentation Fault while using @dynamicCallable #52713

swift-ci opened this issue Apr 4, 2019 · 3 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software type checker Area → compiler: Semantic analysis

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Apr 4, 2019

Previous ID SR-10313
Radar None
Original Reporter jon889 (JIRA User)
Type Bug
Status Resolved
Resolution Done
Environment

Apple Swift version 5.0 (swiftlang-1001.0.69.5 clang-1001.0.46.3)
Target: x86_64-apple-darwin18.2.0
Xcode Version 10.2 (10E125)
macOS 10.14.3 (18D109)

Additional Detail from JIRA
Votes 1
Component/s Compiler
Labels Bug, CompilerCrash, TypeChecker
Assignee @Azoy
Priority Medium

md5: 9d6a9854497e423dedf8540a5d5fd3e6

Issue Description:

I tried to use dynamicCallable to make accessing values in a dictionary easier (seeing as subscripts still can't throw, and the subscript parameter can't be RawRepresentable where RawValue == String 🙁). I thought it was just meant to purely syntactic sugar (and that is why it works before you update to Swift 5), however it's clearly not as explained by the comment at near the end. If I remove the generic parameter and return something like String it works fine.

Here is the minimal code:

struct MissingKeyError: Error {}

@dynamicCallable
class DictionaryBox {
    private var dictionary: [String: Any] = [:]
    
    func dynamicallyCall<T>(withArguments args: [String]) throws -> T {
        guard let value = dictionary[args[0]] as? T else {
            throw MissingKeyError()
        }
        return value
    }
}

func useDictionaryBox() {
    let box = DictionaryBox()
    let value: Bool = try! box("foo")
// If I comment out the above line and comment in the line below it works fine.
//  let value: Bool = try! box.dynamicallyCall(withArguments: ["foo"])
}

The compiler error is:

/Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/ViewController.swift:34:7: error: generic parameter 'T' could not be inferred
        func dynamicallyCall<T>(withArguments args: [String]) throws -> T {
             ^
/Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/ViewController.swift:34:7: note: in call to function 'dynamicallyCall(withArguments:)'
        func dynamicallyCall<T>(withArguments args: [String]) throws -> T {
             ^
Stack dump:
0.  Program arguments: /Applications/Xcode_10_2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -primary-file /Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/ViewController.swift /Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/AppDelegate.swift -emit-module-path /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/Objects-normal/arm64/ViewController~partial.swiftmodule -emit-module-doc-path /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/Objects-normal/arm64/ViewController~partial.swiftdoc -serialize-diagnostics-path /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/Objects-normal/arm64/ViewController.dia -emit-dependencies-path /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/Objects-normal/arm64/ViewController.d -emit-reference-dependencies-path /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/Objects-normal/arm64/ViewController.swiftdeps -target arm64-apple-ios12.2 -Xllvm -aarch64-use-tbi -enable-objc-interop -sdk /Applications/Xcode_10_2.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk -I /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Products/Debug-iphoneos -F /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Products/Debug-iphoneos -enable-testing -g -module-cache-path /Users/jonathan/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -swift-version 5 -enforce-exclusivity=checked -Onone -D DEBUG -serialize-debugging-options -Xcc -working-directory -Xcc /Users/jonathan/Documents/SwiftCompilerCrash -enable-anonymous-context-mangled-names -Xcc -I/Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/swift-overrides.hmap -Xcc -iquote -Xcc /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/SwiftCompilerCrash-generated-files.hmap -Xcc -I/Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/SwiftCompilerCrash-own-target-headers.hmap -Xcc -I/Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/SwiftCompilerCrash-all-target-headers.hmap -Xcc -iquote -Xcc /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/SwiftCompilerCrash-project-headers.hmap -Xcc -I/Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Products/Debug-iphoneos/include -Xcc -I/Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/DerivedSources-normal/arm64 -Xcc -I/Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/DerivedSources/arm64 -Xcc -I/Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/DerivedSources -Xcc -DDEBUG=1 -module-name SwiftCompilerCrash -o /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Build/Intermediates.noindex/SwiftCompilerCrash.build/Debug-iphoneos/SwiftCompilerCrash.build/Objects-normal/arm64/ViewController.o -embed-bitcode-marker -index-store-path /Users/jonathan/Library/Developer/Xcode/DerivedData/SwiftCompilerCrash-eetskdqixhfoencbupvcppwgnsyn/Index/DataStore -index-system-modules 
1.  While type-checking 'useDictionaryBox()' (at /Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/ViewController.swift:42:1)
2.  While type-checking statement at [/Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/ViewController.swift:42:25 - line:46:1] RangeText="{
    let box = DictionaryBox()
    let value: Bool = try! box("foo")
//  let value: Bool = try! box.dynamicallyCall(withArguments: ["foo"])
"
3.  While type-checking declaration 0x7fc5c002e030 (at /Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/ViewController.swift:44:2)
4.  While type-checking expression at [/Users/jonathan/Documents/SwiftCompilerCrash/SwiftCompilerCrash/ViewController.swift:44:20 - line:44:34] RangeText="try! box("foo""
0  swift                    0x0000000112a6aee3 PrintStackTraceSignalHandler(void*) + 51
1  swift                    0x0000000112a6a6bc SignalHandler(int) + 348
2  libsystem_platform.dylib 0x00007fff739d2b3d _sigtramp + 29
3  swift                    0x000000010f9aa4b8 swift::constraints::ConstraintSystem::CacheExprTypes::walkToExprPost(swift::Expr*) + 184
4  swift                    0x000000010f9ac682 (anonymous namespace)::ExprWalker::walkToExprPost(swift::Expr*) + 354
5  swift                    0x000000010fe70c52 swift::ASTVisitor<(anonymous namespace)::Traversal, swift::Expr*, swift::Stmt*, bool, swift::Pattern*, bool, void>::visit(swift::Expr*) + 306
6  swift                    0x000000010fb26da3 swift::TypeChecker::typeCheckExpressionImpl(swift::Expr*&, swift::DeclContext*, swift::TypeLoc, swift::ContextualTypePurpose, swift::OptionSet<swift::TypeCheckExprFlags, unsigned int>, swift::ExprTypeCheckListener&, swift::constraints::ConstraintSystem*) + 3411
7  swift                    0x000000010fb2a1de swift::TypeChecker::typeCheckBinding(swift::Pattern*&, swift::Expr*&, swift::DeclContext*, bool) + 350
8  swift                    0x000000010fb2a96c swift::TypeChecker::typeCheckPatternBinding(swift::PatternBindingDecl*, unsigned int, bool) + 348
9  swift                    0x000000010fb3784f (anonymous namespace)::DeclChecker::visit(swift::Decl*) + 6687
10 swift                    0x000000010fbc8dc8 swift::ASTVisitor<(anonymous namespace)::StmtChecker, void, swift::Stmt*, void, void, void, void>::visit(swift::Stmt*) + 22632
11 swift                    0x000000010fbc3501 bool (anonymous namespace)::StmtChecker::typeCheckStmt<swift::BraceStmt>(swift::BraceStmt*&) + 129
12 swift                    0x000000010fbc2542 swift::TypeChecker::typeCheckAbstractFunctionBodyUntil(swift::AbstractFunctionDecl*, swift::SourceLoc) + 770
13 swift                    0x000000010fbca76e swift::TypeChecker::typeCheckAbstractFunctionBody(swift::AbstractFunctionDecl*) + 558
14 swift                    0x000000010fbe6c82 swift::performTypeChecking(swift::SourceFile&, swift::TopLevelContext&, swift::OptionSet<swift::TypeCheckingFlags, unsigned int>, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int) + 1714
15 swift                    0x000000010f3c54b3 swift::CompilerInstance::performSemaUpTo(swift::SourceFile::ASTStage_t) + 5763
16 swift                    0x000000010e8c32f6 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 838
17 swift                    0x000000010e8bf6de swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 6862
18 swift                    0x000000010e85d7be main + 1246
19 libdyld.dylib            0x00007fff737e7ed9 start + 1
error: Segmentation fault: 11
@belkadan
Copy link
Contributor

belkadan commented Apr 5, 2019

cc @lattner, dan-zheng (JIRA User)

@slavapestov
Copy link
Member

The problem is that when we apply the solution involving a dynamicCallable, CSApply.cpp recursively calls typeCheckExpression() to build the desugared call. Note that it type checks the new expression's constraint system in isolation without binding the expression's type to the expected result. This means that the type parameter T cannot be inferred, so the typeCheckExpression() call can fail. I think what happens then is that we end up with a malformed AST because CSApply does something silly with the return value of typeCheckExpression() there.

I think there are several possible solutions:

  • eliminate the typeCheckExpression() call altogether and build the right CallExpr directly

  • keep the typeCheckExpression(), and bind the return type to the expected type to make this case work

  • handle the failure case correctly, which will prevent this code from working (even though it looks like it should work), however it will avoid the crash

@slavapestov
Copy link
Member

Note that we've been trying to pick off typeCheckExpression() calls from inside CSApply precisely because they cause problems like this, so I would prefer the first solution in the list.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added the crash Bug: A crash, i.e., an abnormal termination of software label Dec 12, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

4 participants