Skip to content
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

[SR-14132] Optional mangled by undefined behavior still shows value in debugDescription #56512

Open
jtbandes opened this issue Jan 30, 2021 · 6 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. standard library Area: Standard library umbrella

Comments

@jtbandes
Copy link
Collaborator

Previous ID SR-14132
Radar rdar://problem/73832531
Original Reporter @jtbandes
Type Bug
Environment
$ swiftc --version
Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Target: arm64-apple-darwin20.2.0 

Reproduces on latest nightly as of 2021/01/30: https://swift.godbolt.org/z/njz9G6

Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Bug
Assignee None
Priority Medium

md5: 429106928692c4c41de8354217e84678

Issue Description:

This code admittedly invokes undefined behavior, but the inconsistency between switch and the string given by debugDescription makes debugging issues of this kind very hard.

(See notes on my journey at https://twitter.com/jtbandes/status/1355639304329060358)

The issue reproduces on latest nightly as of 2021/01/30: https://swift.godbolt.org/z/njz9G6

func foo(_ ptr: UnsafeMutableRawPointer?) {
  // assumes UnsafePointer<Int>, but is actually UnsafePointer<Int?>
  ptr?.assumingMemoryBound(to: Int.self).pointee = 42
}

var val: Int?
foo(&val)
print(val.debugDescription)  // prints "Optional(42)"

switch val {
case .none:
  print("none")              // prints "none"
case .some(let x):
  print("some(\(x))")
}

Neither -sanitize=address nor -sanitize=undefined produce any additional output that could help debug. Turning on optimization doesn't seem to affect the results.

@typesanitizer
Copy link

@swift-ci create

@atrick
Copy link
Member

atrick commented Feb 8, 2021

This is a better way to write the code

@atrick
Copy link
Member

atrick commented Feb 8, 2021

I can clarify the issue a bit:
At -Onone. We have an Optional<Int>:

@jtbandes
Copy link
Collaborator Author

jtbandes commented Feb 8, 2021

The code in foo() was just meant to illustrate what was happening that caused the bug. In reality I was calling a C function and passing it a pointer to the wrong kind of value (because it takes UnsafeMutableRawPointer instead of a more specific kind of pointer: https://developer.apple.com/documentation/coregraphics/1456508-cgpdfobjectgetvalue).

@jtbandes
Copy link
Collaborator Author

jtbandes commented Feb 8, 2021

Calling debugDescription now gives us a non-nil Optional, while switching over the discriminator gives us nil.

Just curious—how does debugDescription decide to print nil or Optional(something) without checking the discriminator?

@atrick
Copy link
Member

atrick commented Feb 8, 2021

A valid `nil` requires all the payload bits to be cleared. I think this is done so that, for more complicated enums, those unused bit positions could be reused for other discriminators. It would appear that debugDescription checks all the bits, and decides it's non-null, whereas the switch only checks the extra discriminator bits. Would be nice if this were consistent.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
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. standard library Area: Standard library umbrella
Projects
None yet
Development

No branches or pull requests

3 participants