swift-colab icon indicating copy to clipboard operation
swift-colab copied to clipboard

Extra slash in error stack trace

Open philipturner opened this issue 2 years ago • 1 comments

I was working on reproducing a crash in swift-reflection-mirror, and successfully reproduced it on a non-Apple platform. The stack trace for the runtime error has slightly incorrect formatting. I never accounted for this type of error message while making Swift-Colab, which is probably why it's improperly formatted. However, I can at least use the stack trace to investigate the crash in ReflectionMirror.

// Cell 1 - pulls from the "colab-crash-1" branch
%install '.package(url: "https://github.com/philipturner/swift-reflection-mirror", .branch("colab-crash-1"))' ReflectionMirror
@_spi(Reflection) import ReflectionMirror
print(_forEachField)
// Cell 2
struct ASimpleKPI {
  var w = 1
}

struct AMixedKPI {
  var string = "foo"
}

struct ANestedKPI {
  var simple = ASimpleKPI()
  var mixed = AMixedKPI()
}
// Cell 3
var x = ANestedKPI()
    
do {
  var result: [PartialKeyPath<ANestedKPI>] = []
  
  var out = [PartialKeyPath<ANestedKPI>]()
  _forEachFieldWithKeyPath(of: ANestedKPI.self, options: .ignoreUnknown) { _, kp in
    out.append(kp)
    return true
  }
  
  for kp in out {
    result.append(kp)
    if x[keyPath: kp] is ASimpleKPI {
      _forEachFieldWithKeyPath(of: ASimpleKPI.self, options: .ignoreUnknown) { _, nkp in
        result.append(kp.appending(path: nkp as AnyKeyPath)!)
        return true
      }
    } else if x[keyPath: kp] is AMixedKPI {
      var out2 = [AnyKeyPath]()
      _forEachFieldWithKeyPath(of: AMixedKPI.self, options: .ignoreUnknown) { _, nkp in
        out2.append(nkp as AnyKeyPath)
        return true
      }
      
      for nkp in out2 {
        result.append(kp.appending(path: nkp)!)
      }
    }
  }
}
// Cell 4
do {
  var result: [PartialKeyPath<ANestedKPI>] = []
  
  var out = [PartialKeyPath<ANestedKPI>]()
  _forEachFieldWithKeyPath(of: ANestedKPI.self, options: .ignoreUnknown) { _, kp in
    out.append(kp)
    return true
  }
  
  for kp in out {
    result.append(kp)
    if x[keyPath: kp] is ASimpleKPI {
      _forEachFieldWithKeyPath(of: ASimpleKPI.self, options: .ignoreUnknown) { _, nkp in
        result.append(kp.appending(path: nkp as AnyKeyPath)!)
        return true
      }
    } else if x[keyPath: kp] is AMixedKPI {
      _forEachFieldWithKeyPath(of: AMixedKPI.self, options: .ignoreUnknown) { _, nkp in
        result.append(kp.appending(path: nkp as AnyKeyPath)!)
        return true
      }
    }
  }
}

Run the cells in this order:

  • Cell 1
  • Cell 2
  • Cell 3
  • Cell 4
  • Cell 3
  • Cell 4

In the second run of Cell 4, there should be a runtime crash. The error message's second stack frame says ReflectionMirror.swift/, with an extraneous slash after swift. The bug occurs in the function prettyPrintStackTrace, inside the file FormatErrors.swift. Permalink here.

Screen Shot 2022-07-06 at 10 20 22 AM

On second examination, the first frame is also incorrect at closure #3 in . There are two spaces between in and -, when I would like only one present.

philipturner avatar Jul 06 '22 14:07 philipturner

Patched in Swift-Colab v2.3. I rewrote the serialization mechanism. Instead of relying on null terminators to denote ends of strings, I put their length as a 4-byte header. Then, I removed the null terminator. Each header had to restart at a 4-byte boundary, which required aligning memory addresses with ~3 & (x + 3).

Screen Shot 2022-08-08 at 8 54 52 PM

To fix the double-spaced function name, I added "main" to it. Whenever LLDB encounters a closure, it writes closure #N in + (space) + (whatever contexts it appears in). I guess it couldn't detect the context. The example below shows more types of contexts that can appear after "in":

Screen Shot 2022-08-08 at 9 05 08 PM

philipturner avatar Aug 09 '22 00:08 philipturner