Skip to content

Conversation

@kovdan01
Copy link
Contributor

@kovdan01 kovdan01 commented Nov 3, 2025

This fixes the following tests which are now crashing due to hitting unreachable "no buffer containing location found" in SourceManager::findBufferContainingLoc:

  • attr/attr_dynamic_member_lookup.swift
  • AutoDiff/Sema/DerivativeRegistrationCrossModule/main.swift
  • Constraints/construction.swift
  • Constraints/members.swift
  • NameLookup/accessibility.swift
  • Sema/call_as_function_simple.swift

The root cause of the crash is as follows. All the tests involve emitting InaccessibleMemberFailure error diagnostic (see
InaccessibleMemberFailure::diagnoseAsError). When DeclNameLoc nameLoc is initialized via default constructor and is not re-assigned with smth meaningful later, the check nameLoc.isValid() returns true even though it should be false. It turns out that we treat const void *LocationInfo as SourceLoc and hope that if LocationInfo is nullptr, casting this to SourceLoc would produce a "default" SourceLoc with Pointer member set to nullptr. But such a cast (see getSourceLocs() member of DeclNameLoc) is undefined behavior. So, the compiler assumes that Pointer member of SourceLoc we try to cast to is not nullptr (due to strict aliasing rule), which leads to nameLoc.isValid() being mistakenly computed as true.

This patch resolves the issue by handling this special case separately.

This fixes the following tests which are now crashing due to hitting
unreachable "no buffer containing location found" in
`SourceManager::findBufferContainingLoc`:

- attr/attr_dynamic_member_lookup.swift
- AutoDiff/Sema/DerivativeRegistrationCrossModule/main.swift
- Constraints/construction.swift
- Constraints/members.swift
- NameLookup/accessibility.swift
- Sema/call_as_function_simple.swift

The root cause of the crash is as follows. All the tests involve emitting
`InaccessibleMemberFailure` error diagnostic (see
`InaccessibleMemberFailure::diagnoseAsError`). When `DeclNameLoc nameLoc`
is initialized via default constructor and is not re-assigned with smth
meaningful later, the check `nameLoc.isValid()` returns `true` even though
it should be `false`. It turns out that we treat `const void *LocationInfo`
as `SourceLoc` and hope that if `LocationInfo` is `nullptr`, casting this
to `SourceLoc` would produce a "default" `SourceLoc` with `Pointer` member
set to `nullptr`. But such a cast (see `getSourceLocs()` member of
`DeclNameLoc`) is undefined behavior. So, the compiler assumes that
`Pointer` member of `SourceLoc` we try to cast to is not `nullptr`,
which leads to `nameLoc.isValid()` being mistakenly computed as `true`.

This patch resolves the issue by handling this special case separately.
@kovdan01 kovdan01 requested a review from asl November 3, 2025 16:12
@kovdan01 kovdan01 marked this pull request as ready for review November 3, 2025 16:18
@kovdan01
Copy link
Contributor Author

kovdan01 commented Nov 3, 2025

Tagging @JaapWijnen

@kovdan01
Copy link
Contributor Author

kovdan01 commented Nov 3, 2025

preset=buildbot_incremental_asan_ubsan,tools=RDA,stdlib=RDA
@swift-ci Please test with preset macOS Platform

@kovdan01
Copy link
Contributor Author

kovdan01 commented Nov 3, 2025

@swift-ci Please test

Copy link
Contributor

@slavapestov slavapestov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incredible, thanks!

@kovdan01
Copy link
Contributor Author

kovdan01 commented Nov 3, 2025

@slavapestov BTW, could you please elaborate if we expect existing main CI jobs enabling UBSan to catch such issues? I see that we have "[main] 7. OSS - LLDB - ASAN + UBSAN - Release - macOS" build job https://ci.swift.org/job/oss-lldb-asan-macos/ (the URL does not include "ubsan" word though). I suppose that this is intended to catch such kinds of issues, isn't it?

Note: to be honest, I was unable to get a message from UBSan locally as well, but just because I was unable to properly set up sanitizer-enabled build in my local development Linux environment in a reasonable timeframe :) I'm sure though that this must be catched by UBSan and we should see the failure on sanitizer-enabled CI jobs.

It would be super helpful if we could have a nice way to catch such bugs on CI since trying to debug them locally is painful and time-consuming.

@slavapestov
Copy link
Contributor

I'm not familiar with UBSan and ASan, sorry. @shahmishal might know.

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow. Excellent debugging on this.

@kovdan01
Copy link
Contributor Author

kovdan01 commented Nov 3, 2025

@swift-ci Please test Windows platform

@kovdan01 kovdan01 merged commit 971e696 into swiftlang:main Nov 4, 2025
6 checks passed
@kovdan01
Copy link
Contributor Author

kovdan01 commented Nov 6, 2025

@shahmishal might know.

@shahmishal Could you please elaborate if we expect existing main CI jobs enabling UBSan to catch UB in the compiler? I see that we have "[main] 7. OSS - LLDB - ASAN + UBSAN - Release - macOS" build job https://ci.swift.org/job/oss-lldb-asan-macos/ (the URL does not include "ubsan" word though). I suppose that this is intended to catch such kinds of issues, isn't it?

It would be super helpful if we could have a nice way to catch such bugs on CI since trying to debug them locally is painful and time-consuming.

elsakeirouz pushed a commit to elsakeirouz/swift that referenced this pull request Nov 6, 2025
…ng#85286)

This fixes the following tests which are now crashing due to hitting
unreachable "no buffer containing location found" in
`SourceManager::findBufferContainingLoc`:

- attr/attr_dynamic_member_lookup.swift
- AutoDiff/Sema/DerivativeRegistrationCrossModule/main.swift
- Constraints/construction.swift
- Constraints/members.swift
- NameLookup/accessibility.swift
- Sema/call_as_function_simple.swift

The root cause of the crash is as follows. All the tests involve
emitting `InaccessibleMemberFailure` error diagnostic (see
`InaccessibleMemberFailure::diagnoseAsError`). When `DeclNameLoc
nameLoc` is initialized via default constructor and is not re-assigned
with smth meaningful later, the check `nameLoc.isValid()` returns `true`
even though it should be `false`. It turns out that we treat `const void
*LocationInfo` as `SourceLoc` and hope that if `LocationInfo` is
`nullptr`, casting this to `SourceLoc` would produce a "default"
`SourceLoc` with `Pointer` member set to `nullptr`. But such a cast (see
`getSourceLocs()` member of `DeclNameLoc`) is undefined behavior. So,
the compiler assumes that `Pointer` member of `SourceLoc` we try to cast
to is not `nullptr` (due to strict aliasing rule), which leads to
`nameLoc.isValid()` being mistakenly computed as `true`.

This patch resolves the issue by handling this special case separately.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants