Skip to content

Commit 664936c

Browse files
committed
[TaskLocal] crash on illegal withValue
1 parent 08fddae commit 664936c

10 files changed

+107
-155
lines changed

include/swift/ABI/TaskLocal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ class TaskLocal {
136136

137137
/// Retrieve a pointer to the storage of the value.
138138
OpaqueValue *getStoragePtr() {
139-
fprintf(stderr, "[%s:%d] (%s) GET STORAGE\n", __FILE__, __LINE__, __FUNCTION__);
140139
return reinterpret_cast<OpaqueValue *>(
141140
reinterpret_cast<char *>(this) + storageOffset(valueType));
142141
}

stdlib/public/Concurrency/TaskLocal.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ void TaskLocal::Storage::initializeLinkParent(AsyncTask* task,
6363

6464
TaskLocal::Item*
6565
TaskLocal::Item::createParentLink(AsyncTask *task, AsyncTask *parent) {
66-
fprintf(stderr, "[%s:%d] (%s) CREATE PARENT LINK\n", __FILE__, __LINE__, __FUNCTION__);
67-
6866
size_t amountToAllocate = Item::itemSize(/*valueType*/nullptr);
6967
// assert(amountToAllocate % MaximumAlignment == 0); // TODO: do we need this?
7068
void *allocation = _swift_task_alloc_specific(task, amountToAllocate);
@@ -112,7 +110,7 @@ static void swift_task_reportIllegalTaskLocalBindingWithinWithTaskGroupImpl(
112110
char *message;
113111
swift_asprintf(
114112
&message,
115-
"error: task-local value: detected illegal task-local value binding at %.*s:%d.\n"
113+
"error: task-local: detected illegal task-local value binding at %.*s:%d.\n"
116114
"Task-local values must only be set in a structured-context, such as: "
117115
"around any (synchronous or asynchronous function invocation), "
118116
"around an 'async let' declaration, or around a 'with(Throwing)TaskGroup(...){ ... }' "
@@ -130,17 +128,17 @@ static void swift_task_reportIllegalTaskLocalBindingWithinWithTaskGroupImpl(
130128
"\n"
131129
" // bind task-local for all tasks spawned within the group\n"
132130
" await <task-local>.withValue(1234) {\n"
133-
" await withTaskGroup(...) { group in \n"
131+
" await withTaskGroup(...) { group in\n"
134132
" group.spawn { ... }\n"
135133
" }\n"
136134
" }\n"
137135
"\n"
138136
"or, inside the specific task-group child task:\n"
139137
"\n"
140138
" // bind-task-local for only specific child-task\n"
141-
" await withTaskGroup(...) { group in \n"
139+
" await withTaskGroup(...) { group in\n"
142140
" group.spawn {\n"
143-
" await <task-local>.withValue(1234) { // OK!\n"
141+
" await <task-local>.withValue(1234) {\n"
144142
" ... \n"
145143
" }\n"
146144
" }\n"
@@ -239,7 +237,6 @@ void TaskLocal::Storage::pushValue(AsyncTask *task,
239237
assert(value && "Task local value must not be nil");
240238

241239
auto item = Item::createLink(task, key, valueType);
242-
fprintf(stderr, "[%s:%d] (%s) here\n", __FILE__, __LINE__, __FUNCTION__);
243240
valueType->vw_initializeWithTake(item->getStoragePtr(), value);
244241
head = item;
245242
}

stdlib/public/Concurrency/TaskLocal.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,11 @@ public final class TaskLocal<Value>: CustomStringConvertible {
6363
self
6464
}
6565

66-
public func withValue<R>(_ valueDuringBody: Value, do body: () async throws -> R) async rethrows -> R {
66+
@discardableResult
67+
public func withValue<R>(_ valueDuringBody: Value, do body: () async throws -> R,
68+
file: String = #file, line: UInt = #line) async rethrows -> R {
6769
// check if we're not trying to bind a value from an illegal context; this may crash
68-
_checkIllegalTaskLocalBindingWithinWithTaskGroup()
70+
_checkIllegalTaskLocalBindingWithinWithTaskGroup(file: file, line: line)
6971

7072
// we need to escape the `_task` since the withUnsafeCurrentTask closure is not `async`.
7173
// this is safe, since we know the task will remain alive because we are running inside of it.
@@ -162,8 +164,7 @@ public func _taskLocalValueGet(
162164

163165
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
164166
@usableFromInline
165-
func _checkIllegalTaskLocalBindingWithinWithTaskGroup(file: String = #file,
166-
line: UInt = #line) {
167+
func _checkIllegalTaskLocalBindingWithinWithTaskGroup(file: String, line: UInt) {
167168
if _taskHasTaskGroupStatusRecord() {
168169
file.withCString { _fileStart in
169170
_reportIllegalTaskLocalBindingWithinWithTaskGroup(

test/Concurrency/Runtime/async_task_locals_async_let.swift

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,23 @@
99
// UNSUPPORTED: back_deployment_runtime
1010

1111
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
12-
enum TaskLocalValues {
13-
struct NumberKey: TaskLocalKey {
14-
static var defaultValue: Int { 0 }
15-
}
16-
var number: NumberKey { .init() }
12+
enum TL {
13+
@TaskLocal
14+
static var number: Int = 0
1715
}
1816

1917
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
2018
@discardableResult
21-
func printTaskLocal<Key>(
22-
_ key: KeyPath<TaskLocalValues, Key>,
23-
_ expected: Key.Value? = nil,
24-
file: String = #file, line: UInt = #line
25-
) -> Key.Value? where Key: TaskLocalKey {
26-
let value = Task.local(key)
27-
print("\(Key.self): \(value) at \(file):\(line)")
19+
func printTaskLocal<V, Key>(
20+
_ key: Key,
21+
_ expected: V? = nil,
22+
file: String = #file, line: UInt = #line
23+
) -> V? where Key: TaskLocal<V> {
24+
let value = key
25+
print("\(value) at \(file):\(line)")
2826
if let expected = expected {
2927
assert("\(expected)" == "\(value)",
30-
"Expected [\(expected)] but found: \(value), at \(file):\(line)")
28+
"Expected [\(expected)] but found: \(value), at \(file):\(line)")
3129
}
3230
return expected
3331
}
@@ -36,14 +34,14 @@ func printTaskLocal<Key>(
3634

3735
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
3836
func async_let_nested() async {
39-
_ = printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}}
40-
async let x1: () = Task.withLocal(\.number, boundTo: 2) {
41-
async let x2 = printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
37+
_ = printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(0)
38+
async let x1: () = TL.$number.withValue(2) {
39+
async let x2 = printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
4240

4341
@Sendable
4442
func test() async {
45-
printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
46-
async let x31 = printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
43+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
44+
async let x31 = printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
4745
_ = await x31
4846
}
4947
async let x3: () = test()
@@ -53,18 +51,18 @@ func async_let_nested() async {
5351
}
5452

5553
_ = await x1
56-
printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}}
54+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(0)
5755
}
5856

5957
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
6058
func async_let_nested_skip_optimization() async {
61-
async let x1: Int? = Task.withLocal(\.number, boundTo: 2) {
59+
async let x1: Int? = TL.$number.withValue(2) {
6260
async let x2: Int? = { () async -> Int? in
6361
async let x3: Int? = { () async -> Int? in
6462
async let x4: Int? = { () async -> Int? in
6563
async let x5: Int? = { () async -> Int? in
66-
assert(Task.local(\.number) == 2)
67-
async let xx = printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
64+
assert(TL.number == 2)
65+
async let xx = printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
6866
return await xx
6967
}()
7068
return await x5

test/Concurrency/Runtime/async_task_locals_basic.swift

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,20 @@ class StringLike: CustomStringConvertible {
1717
var description: String { value }
1818
}
1919

20-
2120
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
22-
enum TaskLocalValues {
21+
enum TL {
2322

2423
@TaskLocal
2524
static var string: String = "<undefined>"
2625

2726
@TaskLocal
2827
static var number: Int = 0
2928

30-
struct NeverKey: TaskLocalKey {
31-
static var defaultValue: StringLike { .init("<never>") }
32-
}
33-
var never: NeverKey { .init() }
34-
35-
struct ClazzKey: TaskLocalKey {
36-
static var defaultValue: ClassTaskLocal? { nil }
37-
}
38-
var clazz: ClazzKey { .init() }
29+
@TaskLocal
30+
static var never: StringLike = "<never>"
3931

32+
@TaskLocal
33+
static var clazz: ClassTaskLocal = nil
4034
}
4135

4236
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
@@ -68,9 +62,9 @@ func printTaskLocal<Key>(
6862

6963
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
7064
func simple() async {
71-
printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}}
72-
await Task.withLocal(\.number, boundTo: 1) {
73-
printTaskLocal(\.number) // CHECK-NEXT: NumberKey: 1 {{.*}}
65+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
66+
await TL.$number.withValue(1) {
67+
printTaskLocal(TL.$number) // CHECK-NEXT: TaskLocal<Int>(1)
7468
}
7569
}
7670

@@ -103,16 +97,16 @@ func simple_throw() async {
10397
func nested() async {
10498
printTaskLocal(\.string) // CHECK: StringKey: <undefined> {{.*}}
10599
await Task.withLocal(\.string, boundTo: "hello") {
106-
printTaskLocal(\.number) // CHECK-NEXT: NumberKey: 0 {{.*}}
100+
printTaskLocal(TL.$number) // CHECK-NEXT: TaskLocal<Int>(2)
107101
printTaskLocal(\.string)// CHECK-NEXT: StringKey: hello {{.*}}
108-
await Task.withLocal(\.number, boundTo: 2) {
109-
printTaskLocal(\.number) // CHECK-NEXT: NumberKey: 2 {{.*}}
102+
await TL.$number.withValue(2) {
103+
printTaskLocal(TL.$number) // CHECK-NEXT: TaskLocal<Int>(2)
110104
printTaskLocal(\.string, "hello") // CHECK: StringKey: hello {{.*}}
111105
}
112-
printTaskLocal(\.number) // CHECK-NEXT: NumberKey: 0 {{.*}}
106+
printTaskLocal(TL.$number) // CHECK-NEXT: TaskLocal<Int>(2)
113107
printTaskLocal(\.string) // CHECK-NEXT: StringKey: hello {{.*}}
114108
}
115-
printTaskLocal(\.number) // CHECK-NEXT: NumberKey: 0 {{.*}}
109+
printTaskLocal(TL.$number) // CHECK-NEXT: TaskLocal<Int>(2)
116110
printTaskLocal(\.string) // CHECK-NEXT: StringKey: <undefined> {{.*}}
117111
}
118112

@@ -138,9 +132,9 @@ func nested_3_onlyTopContributes() async {
138132
printTaskLocal(\.string) // CHECK: StringKey: <undefined> {{.*}}
139133
await Task.withLocal(\.string, boundTo: "one") {
140134
printTaskLocal(\.string)// CHECK-NEXT: StringKey: one {{.*}}
141-
await Task.withLocal(\.number, boundTo: 2) {
135+
await TL.$number.withValue(2) {
142136
printTaskLocal(\.string) // CHECK-NEXT: StringKey: one {{.*}}
143-
await Task.withLocal(\.number, boundTo: 3) {
137+
await TL.$number.withValue(3) {
144138
printTaskLocal(\.string) // CHECK-NEXT: StringKey: one {{.*}}
145139
}
146140
printTaskLocal(\.string) // CHECK-NEXT: StringKey: one {{.*}}

test/Concurrency/Runtime/async_task_locals_groups.swift

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,43 +35,43 @@ func printTaskLocal<V, Key>(
3535
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
3636
func groups() async {
3737
// no value
38-
await withTaskGroup(of: Int.self) { group in
39-
printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}}
38+
_ = await withTaskGroup(of: Int.self) { group in
39+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(0)
4040
}
4141

4242
// no value in parent, value in child
43-
let x1: Int = try! await withTaskGroup(of: Int.self) { group in
43+
let x1: Int = await withTaskGroup(of: Int.self) { group in
4444
group.spawn {
45-
printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}}
45+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(0)
4646
// inside the child task, set a value
47-
await Task.withLocal(\.number, boundTo: 1) {
48-
printTaskLocal(\.number) // CHECK: NumberKey: 1 {{.*}}
47+
_ = await TL.$number.withValue(1) {
48+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(1)
4949
}
50-
printTaskLocal(\.number) // CHECK: NumberKey: 0 {{.*}}
51-
return TaskLocal(\.number) // 0
50+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(0)
51+
return TL.number // 0
5252
}
5353

54-
return try! await group.next()!
54+
return await group.next()!
5555
}
5656
assert(x1 == 0)
5757

5858
// value in parent and in groups
59-
await Task.withLocal(\.number, boundTo: 2) {
60-
printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
59+
await TL.$number.withValue(2) {
60+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
6161

62-
let x2: Int = try! await withTaskGroup(of: Int.self) { group in
63-
printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
62+
let x2: Int = await withTaskGroup(of: Int.self) { group in
63+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
6464
group.spawn {
65-
printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
65+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
6666

67-
async let childInsideGroupChild: () = printTaskLocal(\.number)
68-
await childInsideGroupChild // CHECK: NumberKey: 2 {{.*}}
67+
async let childInsideGroupChild = printTaskLocal(TL.$number)
68+
_ = await childInsideGroupChild // CHECK: TaskLocal<Int>(2)
6969

70-
return TaskLocal(\.number)
70+
return TL.number
7171
}
72-
printTaskLocal(\.number) // CHECK: NumberKey: 2 {{.*}}
72+
printTaskLocal(TL.$number) // CHECK: TaskLocal<Int>(2)
7373

74-
return try! await group.next()!
74+
return await group.next()!
7575
}
7676

7777
assert(x2 == 2)

test/Concurrency/Runtime/async_task_locals_groups_2.swift

Lines changed: 0 additions & 79 deletions
This file was deleted.

test/Concurrency/Runtime/async_task_locals_inherit_never.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func printTaskLocal<Key>(
3333
}
3434

3535
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
36-
enum TaskLocalValues {
36+
enum TL {
3737

3838
struct StringKey: TaskLocalKey {
3939
static var defaultValue: String { .init("<undefined>") }

0 commit comments

Comments
 (0)