Skip to content

Assertion failure: (FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments") when building in Release mode. #64642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fibrechannelscsi opened this issue Mar 27, 2023 · 8 comments · Fixed by #66448
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. CodeGen compiler The Swift compiler itself crash Bug: A crash, i.e., an abnormal termination of software debug info Area → compiler → IRGen: Debug information emission multiple files Flag: An issue whose reproduction requires multiple files optimized only Flag: An issue whose reproduction requires optimized compilation swift 5.9

Comments

@fibrechannelscsi
Copy link
Contributor

fibrechannelscsi commented Mar 27, 2023

Description
The compiler generates an error message when attempting to compile the following code in Release mode. The exact error message is:
Assertion failed: (FragmentOffset >= OffsetInBits && "overlapping or duplicate fragments"), function addFragmentOffset, file DwarfExpression.cpp, line 679.

Steps to reproduce
This reproducer requires four files: two Package.swift files (one is for an internal package), and two regular Swift source files.
The directory tree looks like this:

./Package.swift
./Sources/InternalPackage/Package.swift
./Sources/InternalPackage/Sources/InternalPackage/User.swift
./Sources/ReproducerServer/Auth.swift

Listing for ./Package.swift:

// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
    name: "Reproducer",
    platforms: [.macOS(.v12),],
    products: [
        .library(
            name: "Reproducer",
            targets: ["ReproducerServer"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/vapor/jwt.git", "4.0.0" ..< "5.0.0"),
        .package(url: "https://github.com/vapor/vapor.git", "4.0.0" ..< "5.0.0"),
        .package(url: "https://github.com/vapor/leaf-kit.git", "1.0.0" ..< "2.0.0"),
        .package(url: "https://github.com/vapor/leaf.git", "4.0.0" ..< "5.0.0"),
        .package(url: "https://github.com/apple/swift-nio.git", "2.0.0" ..< "3.0.0"),
        .package(url: "https://github.com/mczachurski/Swiftgger.git", "1.0.0" ..< "2.0.0"),
        .package(name: "InternalPackage", path: "./Sources/InternalPackage"),
    ],
    targets: [
        .target(
            name: "ReproducerServer",
            dependencies: [
                .product(name: "JWT", package: "jwt"),
                .product(name: "Vapor", package: "vapor"),
                .product(name: "InternalPackage", package: "InternalPackage"),
                .product(name: "Leaf", package: "leaf"),
                .product(name: "LeafKit", package: "leaf-kit"),
                .product(name: "NIOCore", package: "swift-nio"),
                .product(name: "Swiftgger", package: "Swiftgger"),
            ],
            swiftSettings: [.unsafeFlags([], .when(platforms: [.macOS, .linux], configuration: .release))]
        )
    ]
)

Listing for ./Sources/InternalPackage/Package.swift:

// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
    name: "InternalPackage",
    platforms: [
        .macOS(.v12),
        .iOS(.v15),
    ],
    products: [
        .library(
            name: "InternalPackage",
            targets: ["InternalPackage"]
        )
    ],
    dependencies: [
        .package(
            url: "https://github.com/apple/swift-collections.git",
            from: "1.0.3"
        ),
        .package(url: "https://github.com/apple/swift-log.git", from: "1.4.2"),
        .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.13.1"),
        .package(url: "https://github.com/vapor/async-kit.git", from: "1.14.0"),
        .package(url: "https://github.com/vapor/sql-kit.git", from: "3.18.0"),
        .package(url: "https://github.com/apple/swift-nio.git", from: "2.38.0"),

    ],
    targets: [
        .target(
            name: "InternalPackage",
            dependencies: [
                .product(name: "Collections", package: "swift-collections"),
                .product(name: "AsyncKit", package: "async-kit"),
                .product(name: "SQLKit", package: "sql-kit"),
                .product(name: "NIO", package: "swift-nio")
            ]
        )
    ]
)

Listing for ./Sources/InternalPackage/Sources/InternalPackage/User.swift:

import Collections; import Foundation; import NIO; import SQLKit
public final class User: SomeObject {
    public init(ID: UUID = UUID(), locked: Bool = false, email: String? = nil, userName: String? = nil) {}
    public struct UserMemberMapping: EmptyProtocol {
        public var email: SomeMapping<String?> { Self.email }
        public static let email: SomeMapping<String?> = .init()
    }
}
public protocol SomeObject: AnyObject, HasMapping {}
public struct Where: EmptyProtocol {
    public enum ValueOperator {case equals}
    public init<D: Encodable, HQM: HasMapping>(_ root: HQM.Type,_ keypath: KeyPath<HQM.UserMemberMapping, SomeMapping<D>>, _ op: ValueOperator,_ value: D) {}
}
public protocol HasMapping {associatedtype UserMemberMapping: EmptyProtocol}
public extension HasMapping {static func instantiateNodes(from db: SomeStorage, sortBy: [any EmptyProtocol] = [], filter whereable: (any EmptyProtocol)? = nil) -> EventLoopFuture<[Self]> {fatalError()}}
public struct SomeMapping<T>{public init() {fatalError()}}
public protocol EmptyProtocol {}
public class SomeStorage {}

Listing for ./Sources/ReproducerServer/Auth.swift:

import Vapor; import Swiftgger; import Foundation; import InternalPackage
func verifyEmail(_ request: Request) async throws -> Response {
    let verificationData: VerifyUserRegisterData
    switch request.method {
        case .GET: verificationData = try request.query.decode(VerifyUserRegisterData.self)
        case .POST: verificationData = try request.content.decode(VerifyUserRegisterData.self)
        default: throw Abort(HTTPResponseStatus.badRequest, reason: "")
    }
    guard let foundUser = try await User.instantiateNodes(from: try request.someDB(), filter: Where(User.self, \.email, .equals, verificationData.email)).get().first else {throw Abort(HTTPResponseStatus.badRequest, reason: "")}
    guard try validateTOTP(token: "a", userKey: "a", allowingBackups: false) else {throw Abort(HTTPResponseStatus.forbidden, reason: " \(verificationData.verificationCode) ")}
    return try await updateUser(request: request, user: User(), key: "a")
}
func updateUser(request: Request, user: User, key: String) async throws -> Response {fatalError()}
func generateTOTP(userKey: String, interval: Int = 30) throws -> TOTP {return TOTP(key: SymmetricKey(data: Data()), digest: .sha1, digits: .six, interval: interval)}
func validateTOTP(token: String, userKey: String, allowingBackups: Bool = true) throws -> Bool {return try generateTOTP(userKey: userKey).generate(time: Date(), range: allowingBackups ? 3 : 1).contains(token)}
public class OAuthServerApplication {
    let vaporApp: Vapor.Application
    public init() throws {fatalError()}
    public func start() throws {try vaporApp.run()}
}
struct VerifyUserRegisterData: Content, Validatable {
    var email: String
    var verificationCode: String
    static func validations(_ validations: inout Validations) {}
}
public func registerAuthenticationRoutes(parentRoute: RoutesBuilder, openApiBuilder: OpenAPIBuilder, routePrefix: String) throws {parentRoute.get("verify") { req async throws -> Response in try await verifyEmail(req)}}
struct OAuthDbKey: StorageKey {typealias Value = SomeStorage}
extension Request {func someDB() throws -> SomeStorage {return self.application.storage[OAuthDbKey.self]!}}

Expected behavior
The compilation should complete successfully.

Environment

  • Swift compiler version info: Fails with toolchains 2023-03-07a and 2023-03-26a.
  • Xcode version info: 14.2
  • Deployment target: M1

Additional Information
Stack trace:

0.	Running pass 'Function Pass Manager' on module '/Users/user/Library/Developer/Xcode/DerivedData/miniOAuth-ejzxbhjdgpeumjagefudqpcypwku/Build/Intermediates.noindex/Reproducer.build/Release/ReproducerServer.build/Objects-normal/x86_64/Auth.o'.
1.	Running pass 'X86 Assembly Printer' on function '@"$s16ReproducerServer11verifyEmaily5Vapor8ResponseCAC7RequestCYaKFTY0_"'
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x00000001075fd890 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x00000001075fcb94 llvm::sys::RunSignalHandlers() + 128
2  swift-frontend           0x00000001075fded0 SignalHandler(int) + 304
3  libsystem_platform.dylib 0x00000001944842a4 _sigtramp + 56
4  libsystem_pthread.dylib  0x0000000194455cec pthread_kill + 288
5  libsystem_c.dylib        0x000000019438e2c8 abort + 180
6  libsystem_c.dylib        0x000000019438d620 err + 0
7  swift-frontend           0x0000000107e316a8 llvm::DwarfExpression::addFragmentOffset(llvm::DIExpression const*) (.cold.2) + 0
8  swift-frontend           0x0000000104a11da8 llvm::DwarfExpression::addWasmLocation(unsigned int, unsigned long long) + 0
9  swift-frontend           0x00000001049ea510 llvm::DwarfCompileUnit::constructVariableDIEImpl(llvm::DbgVariable const&, bool) + 852
10 swift-frontend           0x00000001049e98a4 llvm::DwarfCompileUnit::createAndAddScopeChildren(llvm::LexicalScope*, llvm::DIE&) + 3244
11 swift-frontend           0x00000001049e9ae4 llvm::DwarfCompileUnit::createAndAddScopeChildren(llvm::LexicalScope*, llvm::DIE&) + 3820
12 swift-frontend           0x00000001049eaefc llvm::DwarfCompileUnit::constructSubprogramScopeDIE(llvm::DISubprogram const*, llvm::LexicalScope*) + 168
13 swift-frontend           0x00000001049f95fc llvm::DwarfDebug::endFunctionImpl(llvm::MachineFunction const*) + 1020
14 swift-frontend           0x00000001049ded80 llvm::DebugHandlerBase::endFunction(llvm::MachineFunction const*) + 216
15 swift-frontend           0x00000001049c447c llvm::AsmPrinter::emitFunctionBody() + 10240
16 swift-frontend           0x000000010401ddc0 llvm::X86AsmPrinter::runOnMachineFunction(llvm::MachineFunction&) + 332
17 swift-frontend           0x00000001052c40a4 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 604
18 swift-frontend           0x00000001072fe700 llvm::FPPassManager::runOnFunction(llvm::Function&) + 760
19 swift-frontend           0x0000000107303ab0 llvm::FPPassManager::runOnModule(llvm::Module&) + 60
20 swift-frontend           0x00000001072fec98 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 972
21 swift-frontend           0x0000000102d78a4c swift::compileAndWriteLLVM(llvm::Module*, llvm::TargetMachine*, swift::IRGenOptions const&, swift::UnifiedStatsReporter*, swift::DiagnosticEngine&, llvm::raw_pwrite_stream&, llvm::sys::SmartMutex<false>*) + 396
22 swift-frontend           0x0000000102d7860c swift::performLLVM(swift::IRGenOptions const&, swift::DiagnosticEngine&, llvm::sys::SmartMutex<false>*, llvm::GlobalVariable*, llvm::Module*, llvm::TargetMachine*, llvm::StringRef, swift::UnifiedStatsReporter*) + 3180
23 swift-frontend           0x0000000102d83c04 (anonymous namespace)::LLVMCodeGenThreads::Thread::run() + 468
24 swift-frontend           0x0000000102d83a24 (anonymous namespace)::LLVMCodeGenThreads::runThread(void*) + 12
25 libsystem_pthread.dylib  0x000000019445606c _pthread_start + 14

Note that performing any of these operations causes the build to succeed:

  1. Building in Debug mode.
  2. Moving the contents of User.swift into Auth.swift.
  3. Changing the body of validateTOTP() to simply return true.

This may be similar to this issue:
#55703
however, Autodiff is not involved.

@fibrechannelscsi fibrechannelscsi added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels labels Mar 27, 2023
@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler itself compiler crash crash Bug: A crash, i.e., an abnormal termination of software swift 5.9 CodeGen labels Mar 27, 2023
@asl asl added the debug info Area → compiler → IRGen: Debug information emission label Apr 6, 2023
@asl
Copy link
Contributor

asl commented May 4, 2023

Tagging @asavonic

@AnthonyLatsis AnthonyLatsis added optimized only Flag: An issue whose reproduction requires optimized compilation multiple files Flag: An issue whose reproduction requires multiple files and removed triage needed This issue needs more specific labels labels May 4, 2023
@asl
Copy link
Contributor

asl commented May 10, 2023

@fibrechannelscsi We cannot reproduce via swift build --configuration=release.

And as far as I can see from 0. Running pass 'Function Pass Manager' on module '/Users/user/Library/Developer/Xcode/DerivedData/miniOAuth-ejzxbhjdgpeumjagefudqpcypwku/Build/Intermediates.noindex/Reproducer.build/Release/ReproducerServer.build/Objects-normal/x86_64/Auth.o'. – you're targeting x86-64, not M1.

Will you please double check?

@asl
Copy link
Contributor

asl commented May 10, 2023

Cannot reproduce with swift build --configuration=release --triple=x86_64-apple-macosx either.

For the record, here is the version of the compiler:

Swift version 5.9-dev (LLVM 8ae296ef658f150, Swift 19790be9c2f7a59)

@fibrechannelscsi
Copy link
Contributor Author

Ok, I see the issue. If I run, for example:
/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2023-04-04-a.xctoolchain/usr/bin/swift build -c release
then the build will succeed.
If instead, I compose the four files above, open up ./Package.swift in Xcode, edit the Scheme, and change the Build Configuration to Release, then I see this error. (Here, toolchains 04-04a and up until 05-09a are affected).

@asl
Copy link
Contributor

asl commented May 10, 2023

@fibrechannelscsi can you pick the cmdline? So we can compare the difference?

@fibrechannelscsi
Copy link
Contributor Author

64642A.txt
I've attached the last bit of the command line issued by Xcode right before it hits the compiler crash.

I do see in some cases it's using a different triple (--triple=x86_64-apple-macos12.0), however, using that flag in and of itself on top of -c release could not reproduce the issue.

@asl
Copy link
Contributor

asl commented May 11, 2023

So, the difference is -whole-module-optimization that swiftpm enables by default. The issues only reproduces without WMO. So, to reproduce:

swift build --configuration=release --triple=x86_64-apple-macosx12.0 -v -Xswiftc -no-whole-module-optimization

@asl
Copy link
Contributor

asl commented May 11, 2023

Auth.swift.ll.txt

asavonic added a commit to asavonic/swift that referenced this issue Jun 8, 2023
SIL variables can be split by SILSROA into separate allocations, each having
op_fragment expressions in debug_value (VarInfo.DIExpr). These allocations can
be further split by IRGen (multiple values in Storage argument).

These "nested" fragments refer to the same DI variable, so it is important to
merge them for the LLVM IR DI expression. The compiler used to ignore fragment
expressions from SIL when IRGen fragments were also present. This led to
incorrect DI info generation, and for some cases even triggered assertions in
LLVM X86 CodeGen:

  DwarfExpression.cpp:679: void llvm::DwarfExpression::addFragmentOffset(const
  llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits &&
  "overlapping or duplicate fragments"' failed.

The patch fixes issue swiftlang#64642. The LIT test is a reduced reproducer from that
issue.
asl pushed a commit that referenced this issue Jun 20, 2023
…66448)

SIL variables can be split by SILSROA into separate allocations, each having
op_fragment expressions in debug_value (VarInfo.DIExpr). These allocations can
be further split by IRGen (multiple values in Storage argument).

These "nested" fragments refer to the same DI variable, so it is important to
merge them for the LLVM IR DI expression. The compiler used to ignore fragment
expressions from SIL when IRGen fragments were also present. This led to
incorrect DI info generation, and for some cases even triggered assertions in
LLVM X86 CodeGen:

  DwarfExpression.cpp:679: void llvm::DwarfExpression::addFragmentOffset(const
  llvm::DIExpression *): Assertion `FragmentOffset >= OffsetInBits &&
  "overlapping or duplicate fragments"' failed.

The patch fixes issue #64642. The LIT test is a reduced reproducer from that issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. CodeGen compiler The Swift compiler itself crash Bug: A crash, i.e., an abnormal termination of software debug info Area → compiler → IRGen: Debug information emission multiple files Flag: An issue whose reproduction requires multiple files optimized only Flag: An issue whose reproduction requires optimized compilation swift 5.9
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants