Skip to content

[Autodiff] EXC_BAD_ACCESS when running a @differentiable function in the context of an XCTest. #69238

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

Open
fibrechannelscsi opened this issue Oct 17, 2023 · 2 comments
Labels
AutoDiff bug A deviation from expected or documented behavior. Also: expected but undesirable behavior.

Comments

@fibrechannelscsi
Copy link
Contributor

Description
An EXC_BAD_ACCESS related to a null pointer (0x0) is encountered when attempting to run the unit test below.
Note that this only occurs via the command line; running this in Xcode will not generate a null pointer.

Steps to reproduce
This reproducer requires three files; the directory tree looks like this:

./Package.swift
./Sources/aTest/main.swift
./Tests/aTestTest/test.swift

Listing for Package.swift:

// swift-tools-version: 5.8
import PackageDescription; let package = Package(name: "aTest", targets: [.executableTarget(name: "aTest"), .testTarget(name: "aTestTest", dependencies: [])])

Listing for test.swift:

import _Differentiation; import Foundation; import XCTest
final class Z: XCTestCase {func testA() throws {print(valueWithPullback(at: 2.3, of: m))}}
@differentiable(reverse) private func m(a: Double) -> Double {var c = 0.0; for _ in 0 ... 0 {c = c + 2.4}; return c}

The main.swift file can be blank.

To run via command line, simply run:
swift test

This will generate output like this:

Test Case '-[aTestTest.Z testA]' started.
error: Exited with unexpected signal code 11

To run via lldb, use:

swift build --build-tests
lldb /Applications/Xcode.app/Contents/Developer/usr/bin/xctest ./.build/arm64-apple-macosx/debug/aTestPackageTests.xctest
(lldb) run

Expected behavior
The test should print
(value: 2.4, pullback: (Function))
and exit with an exit code of 0.

Environment

  • Swift compiler version info: 2023-10-08a, 2023-10-15a
  • Xcode version info: N/A
  • Deployment target: macOS 13.6

Additional context
If we remove the control flow in line 3, that is, we replace it with:
@differentiable(reverse) private func m(a: Double) -> Double {var c = 0.0; c = c + 2.4; return c}
then the program will run as expected.

Stack trace (via lldb):

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
  * frame #0: 0x0000000000000000
    frame #1: 0x00000001006ba43c aTestPackageTests`reverse-mode derivative of m(a=0) at test.swift:3:39
    frame #2: 0x00000001006b9d6c aTestPackageTests`thunk for @callee_guaranteed (@unowned Double) -> (@unowned Double, @owned @escaping @callee_guaranteed (@unowned Double) -> (@unowned Double)) at <compiler-generated>:0
    frame #3: 0x0000000213753fd0 libswift_Differentiation.dylib`_Differentiation.valueWithPullback<τ_0_0, τ_0_1 where τ_0_0: _Differentiation.Differentiable, τ_0_1: _Differentiation.Differentiable>(at: τ_0_0, of: @differentiable(reverse) (τ_0_0) -> τ_0_1) -> (value: τ_0_1, pullback: (τ_0_1.TangentVector) -> τ_0_0.TangentVector) + 152
    frame #4: 0x00000001006b9af8 aTestPackageTests`Z.testA(self=0x0000000100a065d0) at test.swift:2:55
    frame #5: 0x00000001006ba064 aTestPackageTests`@objc Z.testA() at <compiler-generated>:0
    frame #6: 0x0000000186024784 CoreFoundation`__invoking___ + 148
    frame #7: 0x00000001860245f8 CoreFoundation`-[NSInvocation invoke] + 428
    frame #8: 0x000000010072d918 XCTestCore`+[XCTFailableInvocation invokeErrorConventionInvocation:completion:] + 96
    frame #9: 0x000000010072d8b0 XCTestCore`__90+[XCTFailableInvocation invokeInvocation:withTestMethodConvention:lastObservedErrorIssue:]_block_invoke + 28
    frame #10: 0x000000010072d40c XCTestCore`__81+[XCTFailableInvocation invokeWithAsynchronousWait:lastObservedErrorIssue:block:]_block_invoke + 356
    frame #11: 0x00000001006ec6d0 XCTestCore`__49+[XCTSwiftErrorObservation observeErrorsInBlock:]_block_invoke + 48
    frame #12: 0x0000000100e640d8 libXCTestSwiftSupport.dylib`function signature specialization <Arg[1] = [Closure Propagated : reabstraction thunk helper from @callee_unowned @convention(block) (@unowned @callee_unowned @convention(block) () -> ()) -> () to @escaping @callee_guaranteed (@unowned @callee_guaranteed () -> ()) -> (), Argument Types : [@callee_unowned @convention(block) (@unowned @callee_unowned @convention(block) () -> ()) -> ()]> of closure #1 () -> () in static __C.XCTSwiftErrorObservation._observeErrors(in: (() -> ()) -> ()) -> () -> Swift.Optional<XCTest.XCTIssue> + 208
    frame #13: 0x0000000100e641d4 libXCTestSwiftSupport.dylib`function signature specialization <Arg[5] = [Closure Propagated : reabstraction thunk helper from @callee_unowned @convention(block) (@unowned @callee_unowned @convention(block) () -> ()) -> () to @escaping @callee_guaranteed (@unowned @callee_guaranteed () -> ()) -> (), Argument Types : [@callee_unowned @convention(block) (@unowned @callee_unowned @convention(block) () -> ()) -> ()]> of function signature specialization <Arg[2] = [Closure Propagated : closure #1 () -> () in static (extension in XCTest):__C.XCTSwiftErrorObservation.(_observeErrors in _B0397D3B80CBC8D7FB9A5B33AB2A74B8)(in: (() -> ()) -> ()) -> () -> Swift.Optional<XCTest.XCTIssue>, Argument Types : [@callee_guaranteed (@unowned @callee_guaranteed () -> ()) -> ()]> of generic specialization <Swift.Optional<XCTest.LocalErrorTracker>, ()> of Swift.TaskLocal.withValue<τ_0_0>(_: τ_0_0, operation: () throws -> τ_1_0, file: Swift.String, line: Swift.UInt) throws -> τ_1_0 + 144
    frame #14: 0x0000000100e63e80 libXCTestSwiftSupport.dylib`function signature specialization <Arg[0] = [Closure Propagated : reabstraction thunk helper from @callee_unowned @convention(block) (@unowned @callee_unowned @convention(block) () -> ()) -> () to @escaping @callee_guaranteed (@unowned @callee_guaranteed () -> ()) -> (), Argument Types : [@callee_unowned @convention(block) (@unowned @callee_unowned @convention(block) () -> ()) -> ()]> of static __C.XCTSwiftErrorObservation._observeErrors(in: (() -> ()) -> ()) -> () -> Swift.Optional<XCTest.XCTIssue> + 916
    frame #15: 0x0000000100e642bc libXCTestSwiftSupport.dylib`@objc static __C.XCTSwiftErrorObservation._observeErrors(in: (() -> ()) -> ()) -> () -> Swift.Optional<XCTest.XCTIssue> + 52
    frame #16: 0x00000001006ec5d8 XCTestCore`+[XCTSwiftErrorObservation observeErrorsInBlock:] + 204
    frame #17: 0x000000010072d1cc XCTestCore`+[XCTFailableInvocation invokeWithAsynchronousWait:lastObservedErrorIssue:block:] + 228
    frame #18: 0x000000010072d84c XCTestCore`+[XCTFailableInvocation invokeInvocation:withTestMethodConvention:lastObservedErrorIssue:] + 372
    frame #19: 0x000000010072dbc8 XCTestCore`+[XCTFailableInvocation invokeInvocation:lastObservedErrorIssue:] + 72
    frame #20: 0x000000010071b748 XCTestCore`__24-[XCTestCase invokeTest]_block_invoke_2 + 88
    frame #21: 0x00000001006f9924 XCTestCore`-[XCTMemoryChecker _assertInvalidObjectsDeallocatedAfterScope:] + 84
    frame #22: 0x0000000100724984 XCTestCore`-[XCTestCase assertInvalidObjectsDeallocatedAfterScope:] + 92
    frame #23: 0x000000010071b6c8 XCTestCore`__24-[XCTestCase invokeTest]_block_invoke.98 + 172
    frame #24: 0x00000001006e51e8 XCTestCore`-[XCTestCase(XCTIssueHandling) _caughtUnhandledDeveloperExceptionPermittingControlFlowInterruptions:caughtInterruptionException:whileExecutingBlock:] + 168
    frame #25: 0x000000010071b24c XCTestCore`-[XCTestCase invokeTest] + 756
    frame #26: 0x000000010071c89c XCTestCore`__26-[XCTestCase performTest:]_block_invoke.154 + 36
    frame #27: 0x00000001006e51e8 XCTestCore`-[XCTestCase(XCTIssueHandling) _caughtUnhandledDeveloperExceptionPermittingControlFlowInterruptions:caughtInterruptionException:whileExecutingBlock:] + 168
    frame #28: 0x000000010071c3e8 XCTestCore`__26-[XCTestCase performTest:]_block_invoke.140 + 516
    frame #29: 0x0000000100702e8c XCTestCore`+[XCTContext _runInChildOfContext:forTestCase:markAsReportingBase:block:] + 180
    frame #30: 0x0000000100702da0 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 144
    frame #31: 0x000000010071c040 XCTestCore`-[XCTestCase performTest:] + 308
    frame #32: 0x00000001006d402c XCTestCore`-[XCTest runTest] + 48
    frame #33: 0x0000000100705a18 XCTestCore`-[XCTestSuite runTestBasedOnRepetitionPolicy:testRun:] + 68
    frame #34: 0x00000001007058f8 XCTestCore`__27-[XCTestSuite performTest:]_block_invoke + 164
    frame #35: 0x00000001007053f8 XCTestCore`__59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 48
    frame #36: 0x0000000100702e8c XCTestCore`+[XCTContext _runInChildOfContext:forTestCase:markAsReportingBase:block:] + 180
    frame #37: 0x0000000100702da0 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 144
    frame #38: 0x0000000100705394 XCTestCore`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 180
    frame #39: 0x0000000100705600 XCTestCore`-[XCTestSuite performTest:] + 216
    frame #40: 0x00000001006d402c XCTestCore`-[XCTest runTest] + 48
    frame #41: 0x0000000100705a18 XCTestCore`-[XCTestSuite runTestBasedOnRepetitionPolicy:testRun:] + 68
    frame #42: 0x00000001007058f8 XCTestCore`__27-[XCTestSuite performTest:]_block_invoke + 164
    frame #43: 0x00000001007053f8 XCTestCore`__59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 48
    frame #44: 0x0000000100702e8c XCTestCore`+[XCTContext _runInChildOfContext:forTestCase:markAsReportingBase:block:] + 180
    frame #45: 0x0000000100702da0 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 144
    frame #46: 0x0000000100705394 XCTestCore`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 180
    frame #47: 0x0000000100705600 XCTestCore`-[XCTestSuite performTest:] + 216
    frame #48: 0x00000001006d402c XCTestCore`-[XCTest runTest] + 48
    frame #49: 0x0000000100705a18 XCTestCore`-[XCTestSuite runTestBasedOnRepetitionPolicy:testRun:] + 68
    frame #50: 0x00000001007058f8 XCTestCore`__27-[XCTestSuite performTest:]_block_invoke + 164
    frame #51: 0x00000001007053f8 XCTestCore`__59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 48
    frame #52: 0x0000000100702e8c XCTestCore`+[XCTContext _runInChildOfContext:forTestCase:markAsReportingBase:block:] + 180
    frame #53: 0x0000000100702da0 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 144
    frame #54: 0x0000000100705394 XCTestCore`-[XCTestSuite _performProtectedSectionForTest:testSection:] + 180
    frame #55: 0x0000000100705600 XCTestCore`-[XCTestSuite performTest:] + 216
    frame #56: 0x00000001006d402c XCTestCore`-[XCTest runTest] + 48
    frame #57: 0x00000001006d5b50 XCTestCore`__89-[XCTTestRunSession executeTestsWithIdentifiers:skippingTestsWithIdentifiers:completion:]_block_invoke + 104
    frame #58: 0x0000000100702e8c XCTestCore`+[XCTContext _runInChildOfContext:forTestCase:markAsReportingBase:block:] + 180
    frame #59: 0x0000000100702da0 XCTestCore`+[XCTContext runInContextForTestCase:markAsReportingBase:block:] + 144
    frame #60: 0x00000001006d5a44 XCTestCore`-[XCTTestRunSession executeTestsWithIdentifiers:skippingTestsWithIdentifiers:completion:] + 296
    frame #61: 0x000000010073a3b0 XCTestCore`__72-[XCTExecutionWorker enqueueTestIdentifiersToRun:testIdentifiersToSkip:]_block_invoke_2 + 136
    frame #62: 0x000000010073a500 XCTestCore`-[XCTExecutionWorker runWithError:] + 108
    frame #63: 0x00000001007000c8 XCTestCore`__25-[XCTestDriver _runTests]_block_invoke.272 + 56
    frame #64: 0x00000001006de460 XCTestCore`-[XCTestObservationCenter _observeTestExecutionForBlock:] + 288
    frame #65: 0x00000001006ffd24 XCTestCore`-[XCTestDriver _runTests] + 1092
    frame #66: 0x00000001006d461c XCTestCore`_XCTestMain + 88
    frame #67: 0x00000001000057d0 xctest`main + 172
    frame #68: 0x0000000185c0bf28 dyld`start + 2236
  thread #2
    frame #0: 0x0000000185f25be8 libsystem_kernel.dylib`__workq_kernreturn + 8
  thread #3
    frame #0: 0x0000000185f25be8 libsystem_kernel.dylib`__workq_kernreturn + 8

@fibrechannelscsi fibrechannelscsi added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels labels Oct 17, 2023
@jkshtj
Copy link
Contributor

jkshtj commented Nov 8, 2023

Did some investigation into this issue and have the following findings.

  1. The issue only happens on mac OS and does not need XCTest at all. In fact a further reduced version of the reproducer can can be put into a single file, compiled with swiftc and the failure will still happen.
import _Differentiation; 
 
@differentiable(reverse)
func m(x: Double) -> Double {
    for _ in 0 ... 0 {} 
    return 1.0
}

let _ = valueWithPullback(at: 2.3, of: m)
  1. The issue is an artifact of some breaking changes that we had to make to fix a memory leak issue in the Swift Autodiff runtime.
  2. The exact cause of the issue is that the code generated by the snapshot toolchain compiler is incompatible with mac OS' system swift-stdlib that is used by the package/executable at runtime.
  3. The code uses autodiff builtin functions that don't exist in mac OS' system swift-stdlib.
  %2 = metatype $@thick (predecessor: _AD__$s4main1m1xS2d_tF_bb3__Pred__src_0_wrt_0).Type // user: %3
  // This function does not exist in mac OS' system swift-stdlib
  %3 = builtin "autoDiffCreateLinearMapContextWithType"(%2 : $@thick (predecessor: 
  ...

@jkshtj
Copy link
Contributor

jkshtj commented Nov 8, 2023

What we need to figure out is how we can use a custom swift-stdlib while running a swift package from the command line, on mac OS.

I have created a post on Swift forum inquiring the same.

@hborla hborla removed the triage needed This issue needs more specific labels label Apr 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AutoDiff bug A deviation from expected or documented behavior. Also: expected but undesirable behavior.
Projects
None yet
Development

No branches or pull requests

4 participants