SwiftLint icon indicating copy to clipboard operation
SwiftLint copied to clipboard

Bus error

Open EvanHahn-Signal opened this issue 2 years ago • 14 comments

New Issue Checklist

Describe the bug

swiftlint lint exits with a bus error when run on my machine, similar to #2391. It happens to me reliably.

See some investigation in the comments below.

Complete output when running SwiftLint, including the stack trace and command used
$ git clone https://github.com/signalapp/Signal-iOS.git
# ...

$ cd Signal-iOS

$ swiftlint lint
# ...lints some files...
# zsh: bus error  swiftlint lint

This also happens with swiftlint lint --quiet and swiftlint lint --no-cache.

The example output is lengthy, but nondeterministic (as far as I can tell).

There isn't an obvious stack trace. (EDIT: See below for a stack trace.)

Environment

  • SwiftLint version: 0.47.1
  • Installation method used: Homebrew
  • Paste your configuration file: public here
  • Are you using nested configurations? No
  • Which Xcode version are you using (check xcodebuild -version)? Xcode 13.4, Build version 13F17a

EvanHahn-Signal avatar Jun 03 '22 16:06 EvanHahn-Signal

I was able to get a stack trace when running it in Xcode.

  • The error seems to reliably happen on this line in SourceKitten.

  • The stack trace makes me think it's caught in some kind of loop, because the trace is quite deep.

  • The error isn't obviously deterministic. In other words, it doesn't seem to happen with the same files each time. Here are the last lines printed before the crash for a few runs:

    Linting 'DeviceTransferOperation.swift' (686/1103)
    
    Linting 'DeviceTransferService+State.swift' (683/1103)
    
    Linting 'DeviceTransferService+Manifest.swift' (88/1103)
    
    Linting 'DeviceTransferService+State.swift' (683/1103)
    
    Linting 'AppUpdateNag.swift' (685/1094)
    
    Linting 'EmojiWithSkinTones+String.swift' (82/1093)
    

    Other than the two that died at ~85, the rest seem to happen at roughly the same time. Not sure what that means, if anything.

I don't know enough about this project and SourceKitten to know what's next, but I hope this investigation helps.

EvanHahn-Signal avatar Jun 03 '22 16:06 EvanHahn-Signal

I was able to repro it.

marcelofabri avatar Jun 08 '22 06:06 marcelofabri

I'm pretty sure EmojiWithSkinTones+String.swift is the file triggering this. SourceKit chokes on it:

➜  Signal-iOS git:(main) sourcekitten syntax --file Signal/src/util/Emoji/EmojiWithSkinTones+String.swift
sourcekit: [1:connection-event-handler:7427: 0.0000] Connection interruptsourcekit: [1:updateSemanticEditorDelay:7427: 0.0003] disabling semantic editor for 10 secondssourcekit: [1:pingService:7427: 0.0003] pinging servicesourcekitten: connection to SourceKitService restored!
Error: Connection interrupted

While debugging locally, I get a crash (looks like a stack overflow) inside SwiftSyntax:

Screen Shot 2022-06-07 at 11 58 59 PM

Hardcoding commandsCache to return [] in SwiftLintFile+Cache crash for me (although SourceKit still chokes on that file). It'd be great to extract confirm in a sample app that SwiftSyntax crashes with this file and file an issue.

marcelofabri avatar Jun 08 '22 06:06 marcelofabri

Here's some additional info just to help with the possible investigation of the issue.

I was able to reproduce a similar crash with the same "bus error" message by running SwiftLint v 0.47.0 on an M1 Mac using SwiftPM (swift run swiftlint).

Here's a minimal file that triggered the crash:

import SwiftUI

struct CrashSwiftLint: View {
    var body: some View {
        VStack {
            VStack {
                VStack {
                    VStack {
                        Text("test")
                            .padding()
                            .padding()
                            .padding()
                            .padding()
                            .padding()
                            .padding()
                            .padding()
                            .padding()
                    }
                }
            }
        }
    }
}

However, swift run swiftlint builds the binary in debug configuration.

When I run SwiftLint in release configuration using swift run -c release swiftlint, it no longer crashes.

Hope that helps.

vadimbelyaev avatar Jun 16 '22 08:06 vadimbelyaev

is there any update on this? running SwiftLint in release configuration results in whole module optimization being used, so we get no benefits of incremental compilation, and build times are thusly incredibly long. any alternatives? consuming SwiftLint via SPM is amazing for aligning team versioning, and I'd rather not switch to using brew if possible

ts0l avatar Jul 20 '22 18:07 ts0l

consuming SwiftLint via SPM is amazing for aligning team versioning, and I'd rather not switch to using brew if possible

I'm using the version from Homebrew and seeing this problem, so I'm not sure if switching to Homebrew will fix it. (But that might conflict with @vadimbelyaev's comment.)

EvanHahn-Signal avatar Jul 25 '22 13:07 EvanHahn-Signal

@EvanHahn-Signal this issue seems to be resolved for me on SwiftLint v0.48.0, if you have time to verify I'd be intrigued to know if it works for you too

ts0l avatar Jul 28 '22 15:07 ts0l

I just tried upgrading to SwiftLint 0.48.0 and still see a bus error, unfortunately.

EvanHahn-Signal avatar Jul 28 '22 16:07 EvanHahn-Signal

I can reproduce this on 0.49.0 as well when running SwiftLint as a Swift executable binary. e.g. swift run swiftlint

SwiftLint will fail on a few different files in our project. Trying to swift run sourcekitten syntax --file on the failing files doesn't show any errors.

Anecdotally, I noticed it seems to dislike complex and nested ternary expressions (which would be a good target for refactoring anyways).

nicorichard avatar Aug 31 '22 15:08 nicorichard

@nicorichard can you please share a sample file that triggers the crash?

jpsim avatar Aug 31 '22 15:08 jpsim

As far as SwiftSyntax crashing in debug builds, that's a known issue. As far as I'm aware it doesn't happen in release builds.

jpsim avatar Aug 31 '22 15:08 jpsim

SwiftSyntax in debug builds has massive stack frames, leading to stack overflows. Those are optimized away in release builds and not an issue from what I've seen.

jpsim avatar Aug 31 '22 15:08 jpsim

I just tested on master with the crashing file from https://github.com/realm/SwiftLint/issues/3988#issuecomment-1157395305 and it doesn't happen anymore in either debug or release:

$ bazel run -c dbg swiftlint -- Crash.swift
INFO: Invocation ID: f1a7c517-03e5-4af4-a0e9-90dada04c7c7
INFO: Build option --compilation_mode has changed, discarding analysis cache.
INFO: Analyzed target //:swiftlint (0 packages loaded, 1499 targets configured).
INFO: Found 1 target...
Target //:swiftlint up-to-date:
  bazel-bin/swiftlint
INFO: Elapsed time: 61.623s, Critical Path: 61.21s
INFO: 66 processes: 32 internal, 22 darwin-sandbox, 12 worker.
INFO: Build completed successfully, 66 total actions
INFO: Build completed successfully, 66 total actions
Linting Swift files at paths Crash.swift
Linting 'Crash.swift' (1/1)
/Users/jsimard/src/SwiftLint/Crash.swift:1:1: warning: File Name Violation: File name should match a type or extension declared in the file (if any). (file_name)
Done linting! Found 1 violation, 0 serious in 1 file.

jpsim avatar Aug 31 '22 15:08 jpsim

The failing code is in an extremely complex and dense file with lots of nesting collections calls (reduce, map) and ternaries. I think it's a little too dense and proprietary to my employer to post though.

Unfortunately, I could not replicate it by attempting to write a minimal reproducible example but after some light refactoring everything works..

Done linting! Found 90 violations, 0 serious in 2060 files.

nicorichard avatar Sep 01 '22 01:09 nicorichard

Here's a reproducible example

[1] 43678 bus error swift run swiftlint lint

import SwiftUI

struct SimplifiedView<Label>: View where Label: View {
    @Binding var step: Int

    private let range: ClosedRange<Int>
    private let label: Label
    private let condition: Bool = false

    public init(
        step: Binding<Int>,
        in range: ClosedRange<Int>,
        @ViewBuilder label: () -> Label
    ) {
        _step = step
        self.range = range
        self.label = label()
    }

    var body: some View {
        HStack {
            HStack {
                Button(action: {}) {
                    if condition {
                        Text("")
                    } else {
                        Text("")
                    }
                }
                .rotationEffect(.degrees(360))
                .buttonStyle(PlainButtonStyle())
                .foregroundColor(.red)
                .disabled(true)
            }
            .padding(.all, 8)
            .background(Color.red)
            .clipShape(Capsule())

            label
        }
        .frame(maxWidth: .infinity, maxHeight: 40, alignment: .trailing)
        .animation(.easeInOut, value: step)
    }
}

even the simplest changes, like commenting out a single line and this will lint.

nicorichard avatar Sep 29 '22 16:09 nicorichard

@nicorichard what version of SwiftLint are you using? I just tried with the source code you posted and it runs fine on macOS:

$ swiftlint --enable-all-rules input.swift
Linting Swift files at paths input.swift
Linting 'input.swift' (1/1)
input.swift:4:14: warning: Explicit ACL Violation: All declarations should specify Access Control Level keywords explicitly. (explicit_acl)
input.swift:20:5: warning: Explicit ACL Violation: All declarations should specify Access Control Level keywords explicitly. (explicit_acl)
input.swift:3:1: warning: Explicit ACL Violation: All declarations should specify Access Control Level keywords explicitly. (explicit_acl)
input.swift:3:1: warning: Explicit Top Level ACL Violation: Top-level declarations should specify Access Control Level keywords explicitly. (explicit_top_level_acl)
input.swift:1:1: warning: File Name Violation: File name should match a type or extension declared in the file (if any). (file_name)
input.swift:10:12: warning: Lower ACL than parent Violation: Ensure definitions have a lower access control level than their enclosing parent (lower_acl_than_parent)
input.swift:23:36: warning: Multiple Closures with Trailing Closure Violation: Trailing closure syntax should not be used when passing more than one closure argument. (multiple_closures_with_trailing_closure)
input.swift:8:26: warning: Redundant Type Annotation Violation: Variables should not have redundant type annotation (redundant_type_annotation)
input.swift:44:1: warning: Trailing Newline Violation: Files should have a single trailing newline. (trailing_newline)
input.swift:10:12: warning: Type Contents Order Violation: An 'initializer' should not be placed amongst the type content(s) 'instance_property'. (type_contents_order)
Done linting! Found 10 violations, 0 serious in 1 file.
$ swiftlint version
0.49.1

jpsim avatar Sep 29 '22 16:09 jpsim

$ swift run swiftlint version

Building for debugging...
Build complete! (0.12s)
0.49.1

You must run SwiftLint via Swift Package Manager using swift run for the error to occur.

nicorichard avatar Sep 29 '22 16:09 nicorichard

You must run SwiftLint via Swift Package Manager using swift run for the error to occur.

As I previously said:

SwiftSyntax in debug builds has massive stack frames, leading to stack overflows. Those are optimized away in release builds and not an issue from what I've seen.

To avoid these stack overflows, please run SwiftLint compiled with -c release when using SwiftPM or with --config=release when using Bazel, or just use the prebuilt release binaries.

jpsim avatar Sep 29 '22 16:09 jpsim