I have a very simple code, but when I call testFunc() it crashes on line value = NSObject() with error EXC_BAD_ACCESS (code=EXC_I386_GPFLT). Could anyone explain, why does it happens?
class A {
var object: Any?
convenience init() {
self.init(nil)
}
private init(_ object: Any?) {
self.object = object
}
}
class B: A {
var value: Any?
func test() {
value = NSObject()
}
}
func testFunc() {
let b = B()
b.test()
}
If I run your code in a Mac command line tool, it works just fine. If I run it as an iOS playground, it crashes.
It looks like a bug in playgrounds to me. (It wouldn't be the first time. I find playgrounds pretty unstable, and tend to test out non-UI coding ideas with command line tools rather than playgrounds because I find playgrounds to be flaky and unreliable.)
I tried adding print statements at various points, and the first time I added a print statement it didn't crash. Then several edit/run cycles later, it didn't crash again. I don't see anything wrong with your code (other than the fact that it doesn't really do anything, and there's no real point in creating an empty NSObject.)
Related
I am not sure if it is a bug or it is really how things should work?
class A {
init() throws { }
}
class B {
lazy var instance = A()
}
this code compiles without mistakes using XCode 9 and latest Swift version, and works perfect unless Class A init() really throws, then lazy var is null pointer. But shouldn't be this code somehow not be compiled?
This is indeed a bug (SR-7862) – you cannot throw errors out of a property initialiser context (and even if you could, you would be required to prefix the call with try), therefore the compiler should produce an error.
I have opened a pull request to fix this (#17022).
Edit: The patch has now been cherry-picked to the 4.2 branch, so it'll be fixed for the release of Swift 4.2 with Xcode 10 (and until the release you can try a 4.2 snapshot).
As an answer to your question:
But shouldn't be this code somehow not be compiled?
Well, at some point your code snippet worked without any issue (because -as you mentioned- the class A init doesn't actually throws), so it could be compiled without any problem. To make it more clear, consider it as a similar case to the following one:
let myString: String? = nil
print(myString!) // crashes!
it will get compiled just fine! although we all know that it crashes when evaluating myString!, i,e we do know it causes a run-time crash, but that doesn't mean that the compiler should prevent it because it could be valid at some point (for instance if we declare it as let myString: String? = "Hello"); Similarly to your case, it could be valid at some point -as mentioned above-.
Usually, for such cases we -as developers- are the responsible to handle it based on what's the desired behavior(s).
Referring to this case, we might need to ask:
"How can we implement the instance lazy variable to catch an error (with a do-catch block)?"
Actually, this code won't compile:
class B {
lazy var instance:A = {
do {
let myA = try A()
return myA
} catch {
print(error)
}
}()
}
complaining that:
Missing return in a closure expected to return 'A'
because obviously reaching the catch block means that there is nothing to be returned. Also, as you mentioned even if you implemented it as
lazy var instance = A()
you will not get a compile-time error, however trying to use it with an actual throwing should leads to run time error:
let myB = B()
print(myB.instance) // crash!
What I would suggest for resolving this issue is to declare instance as lazy optional variable:
class B {
lazy var instance:A? = {
do {
let myA = try A()
return myA
} catch {
print(error)
}
return nil
}()
}
At this point, if we assume that A initializer always throws, trying to access it:
let myB = B()
print(myB.instance)
should log:
caught error
nil
without causing any crash. Otherwise, it should works fine, for instance:
let myB = B()
myB.instance?.doSomething() // works fine
This one has me stumped. I can't figure out why Swift is complaining that self.init is called more than once in this code:
public init(body: String) {
let parser = Gravl.Parser()
if let node = parser.parse(body) {
super.init(document: self, gravlNode: node)
} else {
// Swift complains with the mentioned error on this line (it doesn't matter what "whatever" is):
super.init(document: self, gravlNode: whatever)
}
}
Unless I'm missing something, it's very obvious that it is only calling init once. Funnily enough if I comment out the second line Swift complains that Super.init isn't called on all paths, lol.
What am I missing?
Update:
Ok so the problem was definitely trying to pass self in the call to super.init. I totally forgot I was doing that, ha. I think I had written that experimentally and gotten it to compile and thought that it might actually work, but looks like it's actually a bug that it compiled that way at all.
Anyhow, since passing self to an initializer is kind of redundant since it's the same object, I changed the parent initializer to accept an optional document parameter (it's just an internal initializer so no big deal) and if it's nil I just set it to self in the parent initializer.
For those curious, this is what the parent initializer (now) looks like:
internal init(document: Document?, gravlNode: Gravl.Node) {
self.value = gravlNode.value
super.init()
self.document = document ?? self as! Document
// other stuff...
}
I suspect this is a bad diagnostic (i.e the wrong error message). It would be very helpful if you had a full example we could experiment with, but this line doesn't make sense (and I suspect is the underlying problem):
super.init(document: self, gravlNode: node)
You can't pass self to super.init. You're not initialized yet (you're not initialized until you've called super.init). For example, consider the following simplified code:
class S {
init(document: AnyObject) {}
}
class C: S {
public init() {
super.init(document: self)
}
}
This leads to error: 'self' used before super.init call which I believe is the correct error.
EDIT: I believe Hamish has definitely uncovered a compiler bug. You can exploit it this way in Xcode 8.3.1 (haven't tested on 8.3.2 yet):
class S {
var x: Int
init(document: S) {
self.x = document.x
}
}
class C: S {
public init() {
super.init(document: self)
}
}
let c = C() // malloc: *** error for object 0x600000031244: Invalid pointer dequeued from free list
I'm having this curious issue in which a Playground prints the expected result but at the same time I see an error telling me the execution was stopped because of an EXC_I386_GPFLT error.
I'm using a Playground to model how should an API wrapper I'm writing be used. The idea of doing this is to plan a nice API for future developers.
The following is the entire "planning" code I have written to plan out my wrapper. Feel free to copy and paste it on a Playground to see the problem in action:
class Anilist {
init() {}
internal class UserAPIs {
weak var parent: Anilist? = nil
init(parent: Anilist) {
self.parent = parent
}
}
lazy var user: UserAPIs = { [unowned self] in
let userapi = UserAPIs(parent: self)
return userapi
}()
}
extension Anilist.UserAPIs {
func me(_ completionHandler: (results: [String]) -> Void ) {
// Do some logic, fetching stuff from parent
completionHandler(results: ["Lorem", "Sammet"])
}
}
let andy = Anilist()
andy.user.me { results in
print(results)
}
Curiously, it prints ["Lorem", "Sammet"] properly, but at the same time I get that error.
I have read (for C++) a few other questions regarding this error but unfortunately I haven't been able to solve this issue. For what I can gather is this is happening because I'm attempting to access memory that is nil? In general, I haven't been able to find much information regarding this other than it being an architecture protection.
While the code runs fine, I'm hesitant about putting this on my actual code yet, as I have no idea how it would behave. Even if it works on the first run, it's hard to predict if it will produce errors in the long run.
EDIT:
It looks like it has something to do with the calculated lazy var. Changing that line to this:
lazy var user: UserAPIs = UserAPIs(parent: self)
Works as expected (as in, it prints the array and doesn't give me the EXC_I386_GPFLT error).
EDIT 2:
Previous edit seems to be inaccurate information.
This isn't an answer really but a workaround till I figure out why this works:
let andy = Anilist()
let someVar = andy.user.me { results in
print(results)
}
This gives a compile time warning saying constant someVar inferred to have type (), which maybe unexpected.
But doing this:
let andy = Anilist()
let _ = andy.user.me { results
print(results)
}
works fine WITHOUT any errors at all. Weird enough. It'd be really good if someone could explain why this happens.
I am reading the Dancing in the Debugger — A Waltz with LLDB article. And I am trying the thread return command with Swift 2.2 as well as Swift 3.0.
My code is pretty simple:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let resust = test()
print(resust)
}
func test() -> Bool {
return true
}
}
and I added a breakpoint at the beginning of the test() function with a thread return false action. However, after command+R, my program stops at the breakpoint as expect, but with the following error:
"error: Error returning from frame 0 of thread 1: We only support setting simple integer and float return types at present.."
Here's a screen shot:
Then I tried the same in Objective-C code; everything goes well.
These are known bugs. The value types in Swift (Int, Bool, etc.) are all complex objects, and we haven't taught lldb how to overwrite the return values for them. Error handling will also make this tricky.
In general, forced returns are unsafe - more so with ARC and even more so with Swift, since you are likely to unbalance reference counts - not just on locals but potentially on objects passed in.
I'm currently trying to debug crashes in a JavascriptCore implementation of an interface for native code to perform some work on behalf of the javascript code in the WebView.
The crash sometimes occurs very soon after launching the application, other times it may take a few minutes of executing hundreds of calls to the native code for it to occur.
These are the top two lines for the backtrace of every crash:
(lldb) thread backtrace
* thread #1: tid = 0x37960c, 0x00007fff8de6ecca JavaScriptCore`sanitizeStackForVMImpl + 15, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x700001a2c000)
frame #0: 0x00007fff8de6ecca JavaScriptCore`sanitizeStackForVMImpl + 15
Here is a simplified version of my view controller:
class MyViewController: NSViewController, WebFrameLoadDelegate {
let worker = Worker()
// other setup code...
func webView(webView: WebView!, didCreateJavaScriptContext context: JSContext!, forFrame frame: WebFrame!) {
context.setObject(worker, forKeyedSubscript: "ClientWorker")
}
}
The JSExport protocol itself, and implementation of the code performing work. For testing I removed the actual work and just return a dictionary with dummy data, and the crash still occurs.
#objc protocol WorkerJSExports: JSExport {
func doWork(params: [String:AnyObject], callback: JSValue)
}
#objc class Worker: NSObject, WorkerJSExports {
func doWork(params: [String:AnyObject], callback: JSValue) {
executeBackground(callback) {
return [
"test": "data"
]
}
}
private func executeBackground(callback: JSValue!, f: ()->([String:AnyObject])) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
let result = f()
dispatch_sync(dispatch_get_main_queue()) {
self.executeCallback(callback, result: result)
}
}
}
private func executeCallback(callback: JSValue!, result: AnyObject) {
callback.context.evaluateScript("setTimeout").callWithArguments([callback, 0, result])
}
}
The executeBackground and executeCallback methods are helper functions, and executeCallback is making use of setTimeout in response to what I read in this SO post/answer: JavaScriptCore -- Passing a function as a parameter to ObjC and it seems to have resolved other crashes related to locking.
When I swap out executeBackground for the following function that runs just on the main thread, I have not been able to replicate the crash:
private func executeMain(callback: JSValue!, f: ()->([String:AnyObject])) {
dispatch_async(dispatch_get_main_queue()) {
self.executeCallback(callback, result: f())
}
}
It seems that there is some sort of issue that occurs when passing data created in a background thread into the WebView, but after pouring through the documentation I'm uncertain that what could be. The only taboo I found mentioned was passing data between multiple JSVirtualMachine instances, which doesn't seem applicable since I'm only interacting with a single WebView instance. Any assistance in figuring this out is greatly appreciated!
Update
I seem to have solved the issue by switching out the use of Grand Central Dispatch directly for NSOperationQueues. After changing executeBackground to the following, the crashes have not recurred.
private let workerQueue = NSOperationQueue()
private func executeAsync(callback: JSValue!, f: ()->([String:AnyObject])) {
self.workerQueue.addOperationWithBlock({
let result = f()
NSOperationQueue.mainQueue().addOperationWithBlock({
self.executeCallback(callback, result: result)
})
})
}
Though I can't really prove that this has fixed the crash, we've done fairly extensive testing of this functionality and haven't seen it again. The reason I didn't post this an an answer to my own question is that I'm at a loss as to why exactly this is different and/or better. If anyone has insight into what the change to NSOperationQueues may have solved, it would be very much appreciated!