tera
January 17, 2023, 5:19pm
1
Spent quite a few minutes now before realising that global declaration must be placed before "foo()":
// main.swift
func foo() {
dict["hello"] = "world" // π Thread 1: EXC_BAD_ACCESS (code=1, address=0x8)
}
foo()
var dict: [String : String] = [:]
Could we improve it?
either make it a compilation error
or make it work without crashing
if not the above then improve the crash diagnostic to make it more obvious what's going on.
Minimal example:
// main.swift
let x = hello == "world" // π Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)
var hello = "world"
I think this is a problem because Swift follows a Top-down approach whereby variables must be initialized before usage.
You can also make it a lazy variable too
etcwilde
(Evan Wilde)
January 18, 2023, 2:07pm
4
opened 03:39AM - 11 Jan 22 UTC
bug
compiler
| | |
|------------------|-----------------|β¦
|Previous ID | SR-15713 |
|Radar | rdar://84128006 |
|Original Reporter | @mhjacobson |
|Type | Bug |
Attachment: [Download](https://user-images.githubusercontent.com/2727770/164964420-332dfce2-c968-48ea-9b87-5e11b0e20f63.gz)
<details>
<summary>Environment</summary>
macOS v10.15 Catalina (19H1417)
MacBookAir6,2
Xcode 12.4 (12D4e)
``` java
$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -v
Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Target: x86_64-apple-darwin19.6.0
```
</details>
<details>
<summary>Additional Detail from JIRA</summary>
| | |
|------------------|-----------------|
|Votes | 0 |
|Component/s | Compiler |
|Labels | Bug |
|Assignee | @etcwilde |
|Priority | Medium |
md5: 5f959edc50f7b7263045016bb88930f3
</details>
**Issue Description:**
The TSPL book [says](https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID263):
Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties. Unlike lazy stored properties, global constants and variables donβt need to be marked with the lazy modifier.
However, at least in some cases, that appears not to be true. Take this simple example. Assume \`processAgeInSeconds()\` returns the number of seconds since the process was spawned (which on Darwin can be gleaned through the \`libproc\` APIs):
``` swift
// global scope
let ageString = String(processAgeInSeconds())
sleepThenLog()
func sleepThenLog() {
sleep(10)
print("ageString initialized \(ageString) seconds after launch")
}
```
Since the value placed into \`ageString\` (almost always) ends up being less than ten, it's clear that \`ageString\` is being initialized prior to its first (and only) use inside \`sleepThenLog()\`. (This can be confirmed more strictly with breakpoints, but I figured this was more accessible.)
Things get even stranger if you place the call to \`sleepThenLog()\` before the definition of \`ageString\`, like this:
``` swift
sleepThenLog()
let ageString = String(processAgeInSeconds())
```
In this case, not only does the use of \`ageString\` inside \`sleepThenLog()\` not initialize \`ageString\`; the resultant use of an apparently uninitialized \`String\` then crashes! This makes sense given what I know, but it also seems very unlike Swift to allow access to an uninitialized value.
``` java
(lldb) bt
* thread #​1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x18)
frame #​0: 0x00007fff69a299e8 libswiftCore.dylib`Swift._StringObject.getSharedUTF8Start() -> Swift.UnsafePointer<Swift.UInt8> + 24
frame #​1: 0x00007fff69a29a0e libswiftCore.dylib`Swift._StringObject.sharedUTF8.getter : Swift.UnsafeBufferPointer<Swift.UInt8> + 14
frame #​2: 0x00007fff69a22c7a libswiftCore.dylib`Swift._StringGuts.append(Swift._StringGutsSlice) -> () + 970
frame #​3: 0x00007fff699bc1e6 libswiftCore.dylib`Swift._StringGuts.append(Swift._StringGuts) -> () + 166
frame #​4: 0x00007fff699bbf9a libswiftCore.dylib`Swift.String.write<A where A: Swift.TextOutputStream>(to: inout A) -> () + 26
frame #​5: 0x0000000100002add TestUninitialized`sleepThenLog() [inlined] inlined generic function <Swift.DefaultStringInterpolation> of protocol witness for Swift.TextOutputStreamable.write<A where A1: Swift.TextOutputStream>(to: inout A1) -> () in conformance Swift.String : Swift.TextOutputStreamable in Swift at <compiler-generated>:0 [opt]
frame #​6: 0x0000000100002ac8 TestUninitialized`sleepThenLog() [inlined] generic specialization <Swift.String> of Swift.DefaultStringInterpolation.appendInterpolation<A where A: Swift.CustomStringConvertible, A: Swift.TextOutputStreamable>(A) -> () at <compiler-generated>:0 [opt]
* frame #​7: 0x0000000100002ac8 TestUninitialized`sleepThenLog() at main.swift:13 [opt]
frame #​8: 0x00000001000029bc TestUninitialized`main at main.swift:8:1 [opt]
frame #​9: 0x00007fff6a28acc9 libdyld.dylib`start + 1
```
It's possible these are not considered compiler bugs, but if so, then at least it seems like the book should be corrected.
Yep weβre aware. Iβll find some time one of these days.
2 Likes