after investigating further, it looks like bug #3, or at least a variant of it does in fact affect the 5.5-RELEASE toolchain.
a modified example program to reproduce this problem is given below:
struct Users
{
enum Access
{
case guest
case admin(Int)
case developer(Int, Int, Int, Int)
}
private
actor User
{
init()
{
}
func set(permissions:(Int, Access?))
{
print(permissions)
}
}
private
let users:[Int: User] = [0: .init()]
func set(permissions:(Int, Access?)) async
{
print(permissions)
guard let user:User = self.users[permissions.0]
else
{
print(" \(permissions.0) ")
return
}
await user.set(permissions: permissions)
}
}
@main
enum Main
{
static
func main() async
{
let coordinator:Users = .init()
let stream:AsyncStream<Int> = .init
{
for i in 0 ..< 10
{
$0.yield(i)
}
$0.finish()
}
for await i:Int in stream
{
if i != 0
{
continue
}
await coordinator.set(permissions: (i, .guest))
}
}
}
$ swiftc --version
Swift version 5.5 (swift-5.5-RELEASE)
Target: x86_64-unknown-linux-gnu
$ swiftc -O -parse-as-library async-stack-corruption-5.5.swift
$ ./async-stack-corruption-5.5
(0, Optional(main.Users.Access.admin(144)))
(0, Optional(main.Users.Access.admin(144)))
moreover, while investigating this bug, i also noticed that i could influence the specific enum cases that the real values are overwritten with based on user input. this means that (alongside SR-15225) SR-15240 represents a major security vulnerability in Swift 5.5. it is also highly chaotic — removing or reordering any of the print
statements in this program completely changes the behavior — so it is extremely likely that a minor change in your codebase before a release could silently introduce a vulnerability.
again, i would urge anyone using the 5.5-RELEASE toolchain to either avoid concurrency features, or assume that all binaries compiled with it are compromised.