Swift Concurrency: DEP access violation on Task deallocation

Simple code always produce access violation exception on Windows

import Foundation

func test() async -> String {
    return "Test"
}

@main
struct App {
    static func main() async {

        Task {
            print("Hello")
        }

        let str = await test()
        print(str)
        RunLoop.main.run()
    }
}
C:\Users\gungravekoga\CLionProjects\untitled\.build\debug>C:\drmingw\bin\catchsegv.exe .\untitled.exe
FTH: (13720): *** Fault tolerant heap shim applied to current process. This is usually due to previous crashes. ***
Test
Hello
untitled.exe caused an Access Violation at location 000001EB4CDF0000 DEP violation at location 000001EB4CDF0000.

AddrPC           Params
000001EB4CDF0000 00007FFFC6BEBEEE 0000000000000000 000001EB4CE420B0
000001EB4CDF0000 0000000000000000 000001EB4CE420B0 000001EB4CE2F8B0
00007FFFC6BEBEEE 00007FFF8124FEB0 00007FFFC6BEBEEE 00007FFFC66E7040  swift_Concurrency.dll!swift_task_dealloc
00007FF726F91972 0000000000000001 0000000000000002 0000006F6C6C6548  untitled.exe!$s8untitled3AppV4mainyyYaFZ
0000000100000003 0000000000000002 0000006F6C6C6548 E500000000000000
0000000000000001 0000006F6C6C6548 E500000000000000 0000000000000000
0000000000000002 E500000000000000 0000000000000000 00007FFF8154A948
0000006F6C6C6548 0000000000000000 00007FFF8154A948 0000000000000000
E500000000000000 00007FFF8154A948 0000000000000000 80000400A20B0C1C

Is there some workaround for such a problem or is this a bug in the swift compiler?

I think the issue here is that you are calling RunLoop.main.run(). The main function calls dispatchMain() under the hood. I suspect that it is causing the issue. I can't reproduce the issue when removing RunLoop.main.run(). If you want to wait for the task to print "Hello" you can just await it, i.e. by storing the task and awaiting its value

func test() async -> String {
    return "Test"
}

@main
struct App {
    static func main() async {
        let task = Task {
            print("Hello")
        }

        let str = await test()
        print(str)
        await task.value
    }
}

Thanks for the answer. But on Windows, disaptchMain () doesn't work at all, and the executable exits after the dispatchMain () function is called.
In your example, I have another call stack on access violation

import Foundation

func test() async -> String {
    return "Test"
}

@main
struct App {
    static func main() async {

        let t = Task {
            print("Hello")
        }

        let str = await test()
        print(str)
        //RunLoop.main.run()
        await t.value
    }
}
C:\Users\gungravekoga\CLionProjects\untitled\.build\debug>C:\drmingw\bin\catchsegv.exe .\untitled.exe
FTH: (5928): *** Fault tolerant heap shim applied to current process. This is usually due to previous crashes. ***
Test
untitled.exe caused an Access Violation at location 000000ED49CFFA60 DEP violation at location 000000ED49CFFA60.

AddrPC           Params
000000ED49CFFA60 00007FFFC6C12A30 00007FFF81FB7E58 0000020D3D66EE90
00007FFFC6C12AC0 00007FFF81FB7E58 0000020D3D66EE90 0000020D3D66EE90  swift_Concurrency.dll!$sScPMn
00007FFFC6C12A30 0000020D3D66EE90 0000020D3D66EE90 00007FF640461424  swift_Concurrency.dll!$sScTMn
00007FFF81FB7E58 0000020D3D66EE90 00007FF640461424 0000000000000000  swiftCore.dll!$sytN
0000020D3D66EE90 00007FF640461424 0000000000000000 0000020D3D67FCB0
0000020D3D66EE90 0000000000000000 0000020D3D67FCB0 0000020D3D66FAE0
00007FF640461424 0000000000000000 00007FFFC6C0BD17 0000000000000000  untitled.exe!$s8untitled3AppV4mainyyYaFZ
00007FF640461334 0000000000000000 00007FFFC6C0BD17 0000000000000000  untitled.exe!$s8untitled3AppV4mainyyYaFZ
00007FF640461BF1 0064006C00690075 003600380078005C 0000000000000000  untitled.exe!$s8untitled3AppV5$mainyyYaFZ
00007FF640461D6C 0000000000000000 00007FFFC6C0BD17 0000000000000000  untitled.exe!$s8untitled3AppV5$mainyyYaFZ
00007FF6404629A6 0000000000000000 00007FFFD71400A6 0000000000000130  untitled.exe!$s8untitled3AppVMa
00007FF640461F54 0000000000000000 0000000000000000 000000ED00000000  untitled.exe!main
00007FFFC6C0BAD2 00007FF640461EF0 0000000000000000 0000000000000000  swift_Concurrency.dll!swift_continuation_await
00007FFFC6C08B9D 0000000000000000 0000000000000000 0000000000000000  swift_Concurrency.dll!$ss27AsyncThrowingFilterSequenceV8IteratorV10isIncludedySb7ElementQzYaKcvg
00007FFFC6C092E7 0000000000000000 00007FF640462F69 000000000000001F  swift_Concurrency.dll!swift_job_run
00007FF640461E52 0000000000000000 00007FF640462E29 0000000000000000  untitled.exe!main
00007FF640462DB0 0000000000000000 0000000000000000 0000000000000000  untitled.exe!$s8untitled3AppVMa
00007FFFD7B654E0 0000000000000000 0000000000000000 0000000000000000  KERNEL32.DLL!BaseThreadInitThunk
00007FFFD956485B 0000000000000000 0000000000000000 0000000000000000  ntdll.dll!RtlUserThreadStart

I don't see this behaviour at all. Building and running your sample as:

> swiftc -sdk %SDKROOT% -parse-as-library -emit-executable -o dep.exe dep.swift
> .\dep
Test
Hello
<hang>

Seems to be fine. What build of Swift are you using?

C:\Users\gungravekoga\CLionProjects\untitled\.build\debug>swift --version
compnerd.org Swift version 5.5.2 (swift-5.5.2-RELEASE)
Target: x86_64-unknown-windows-msvc

Building via SPM C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr\bin\swift.exe build --skip-update --product untitled --build-path C:\Users\gungravekoga\CLionProjects\untitled\.build

//Package.swift
import PackageDescription

let package = Package(
    name: "untitled",
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .executableTarget(
            name: "untitled",
            dependencies: [],
                swiftSettings: [
                    .unsafeFlags([
                        "-g",
                        "-debug-info-format=codeview"
                    ])
                ]),
        .testTarget(
            name: "untitledTests",
            dependencies: ["untitled"]),
    ]
)

Interesting; I wonder if this is something that was fixed later. I would recommend that you use nightly snapshots or build swift from source if you are trying to work with async as there has been a bunch of stability work that has gone into main. It is unlikely that we would get this resolved in a 5.5 update, but hopefully 5.6 should have the fix for this.

2 Likes

The following code works most of the time with Swift 5.5 on Windows, but every five times or so it gets stuck before printing anything:

import Foundation

@main
struct AsyncTest {
    
    static func main() async throws {
		let myActor = await MyActor(name: "hello")
		await myActor.say()
		exit(0)
	}
}

actor MyActor {
    
    let name: String
    
    init(name: String) async {
        self.name = name
    }
	
	func say() async {
		print(name)
	}
}

A more complicated code that I have using actors and async/await practically never works on Windows (the outcome until it does not work anymore seems to be random).

I really hope that my problem has the same source (probably is has), and that it gets resolved soon. Could the snapshot from December 23, 2021 December 6, 2021 already resolve it? (I'll try out.)

UPDATE: Yes :slight_smile: it works with 5.6-dev (LLVM 542eceb110d8480, Swift 4323d2fa26a6bf8) (snapshot from December 6, 2021), both my little example and my bigger project mentioned. Very glad to see the Windows version of Swift proceeding in a good direction! Thanks a lot. SPM seems also to work very fine.

2 Likes

Thanks a lot for reporting and looping back to the thread with the update that 5.6-dev is working well, @sspringer. Got me worried there for a moment, glad that it seems to be fixed. Happy holidays :slight_smile: