Skip to content

[stdlib] Add build option to enable _debugPrecondition in Release mode #41445

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

Merged
merged 2 commits into from
Feb 22, 2022

Conversation

lorentey
Copy link
Member

It is sometimes desirable to always perform (relatively cheap) runtime checks in the stdlib, even in configurations where we’d otherwise elide them.

Add a build-time option to the standard library (SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE) to make _debugPrecondition work like _precondition, i.e., to enable it even in ReleaseAssert configurations.

This option will keep additional checks in the following places, even in release mode:

  • Range checking in the subscript operations of all unsafe buffer pointer types.
  • Nil checking in Optional.unsafelyUnwrapped
  • Additional argument validation in Unsafe[Mutable][Raw]Pointer’s initialization/assignment/move/deinitialization/binding methods
  • Protection against initializing Unsafe[Mutable][Raw]Pointer with invalid data. (Negative count, nil pointer for non-empty buffer, etc)
  • Checks against index overflow in Unsafe[Mutable]BufferPointer’s index manipulation methods
  • Checks against backward ranges in Range(uncheckedBounds:), ClosedRange(uncheckedBounds:)
  • Dynamic isa check in unsafeDowncast(_:to:)
  • Additional [cheap] checks to catch invalid Sequence/Collection implementations in Array.init<S:Sequence>(_:) and elsewhere
  • Checks against Character containing multiple grapheme clusters
  • More index validation in EmptyCollection

(Additional cases will get added as the stdlib evolves.)

The option is disabled by default — so _debugPreconditions continue to be disabled in optimized builds, even after this change lands, unless someone specifically builds a stdlib that enables them.

rdar://89118585

@lorentey
Copy link
Member Author

@swift-ci test

@lorentey lorentey requested a review from glessard February 18, 2022 01:53
@stephentyrone
Copy link
Contributor

I am mildly worried about testing this, since the stdlib is not built this way in CI. What's the plan?

@lorentey
Copy link
Member Author

Building a throwaway stdlib configuration would be prohibitively expensive, so I'm thinking we'll just let this setting go untested in regular CI jobs, like we do with runtime counters, Array's cow checks, SWIFT_STDLIB_ENABLE_UNICODE_DATA etc.

We have additional CI instances dedicated to specialized configurations, and this will be covered by at least one of them.

The updated Asserts.swift test should catch cases where _debugPrecondition doesn't work like _isStdlibDebugChecksEnabled promises, although I really should add a new lit test to verify that its return value is consistent with the new build flag. That's simple enough to do -- I just need to also patch it through as a lit feature flag. 🤔

Update incoming.

@lorentey
Copy link
Member Author

Ah, there is also the fact that parts of our unit tests are currently looking at _isDebugAssertConfiguration to figure out whether to expect traps for the cases above. Oh well, more updates incoming.

It is sometimes desirable to always perform (relatively cheap) runtime checks in the stdlib, even in configurations where we’d otherwise elide them.

Add a build-time option to the standard library (`SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE`) to make `_debugPrecondition` work like `_precondition`, i.e., to enable it even in ReleaseAssert configurations.

This option will keep additional checks in the following places, even in release mode:

- Range checking in the subscript operations of all unsafe buffer pointer types.
- Nil checking in `Optional.unsafelyUnwrapped`
- Additional argument validation in `Unsafe[Mutable][Raw]Pointer`’s initialization/assignment/move/deinitialization/binding methods
- Protection against initializing `Unsafe[Mutable][Raw]Pointer` with invalid data. (Negative count, nil pointer for non-empty buffer, etc)
- Checks against index overflow in `Unsafe[Mutable]BufferPointer`’s index manipulation methods
- Checks against backward ranges in `Range(uncheckedBounds:)`, `ClosedRange(uncheckedBounds:)`
- Dynamic isa check in `unsafeDowncast(_:to:)`
- Additional [cheap] checks to catch invalid Sequence/Collection implementations in `Array.init<S:Sequence>(_:)` and elsewhere
- Checks against `Character` containing multiple grapheme clusters
- More index validation in `EmptyCollection`

(Additional cases will get added as the stdlib evolves.)

The option is disabled by default — so `_debugPrecondition`s continue to be disabled in optimized builds, even after this change lands, unless someone specifically builds a stdlib that enables them.

rdar://89118585
@lorentey lorentey force-pushed the unconditional-debugPrecondition branch from b2c78ac to 5274295 Compare February 19, 2022 05:55
@lorentey
Copy link
Member Author

@swift-ci test

@lorentey
Copy link
Member Author

🤔

Failed Tests (50):
  Swift(macosx-x86_64) :: bindings-build-record.swift
  Swift(macosx-x86_64) :: chained-additional-kinds-fine.swift
  Swift(macosx-x86_64) :: chained-after-fine.swift
  Swift(macosx-x86_64) :: chained-fine.swift
  Swift(macosx-x86_64) :: chained-private-after-fine.swift
  Swift(macosx-x86_64) :: chained-private-after-multiple-fine.swift
  Swift(macosx-x86_64) :: chained-private-after-multiple-nominal-members-fine.swift
  Swift(macosx-x86_64) :: chained-private-fine.swift
  Swift(macosx-x86_64) :: check-interface-implementation-fine.swift
  Swift(macosx-x86_64) :: crash-added-fine.swift
  Swift(macosx-x86_64) :: crash-new-fine.swift
  Swift(macosx-x86_64) :: crash-simple-fine.swift
  Swift(macosx-x86_64) :: dependencies-preservation-fine.swift
  Swift(macosx-x86_64) :: driver-show-incremental-arguments-fine.swift
  Swift(macosx-x86_64) :: driver-show-incremental-conflicting-arguments-fine.swift
  Swift(macosx-x86_64) :: driver-show-incremental-inputs-fine.swift
  Swift(macosx-x86_64) :: driver-show-incremental-malformed-fine.swift
  Swift(macosx-x86_64) :: driver-show-incremental-mutual-fine.swift
  Swift(macosx-x86_64) :: driver-show-incremental-swift-version-fine.swift
  Swift(macosx-x86_64) :: embed-bitcode-parallel-fine.swift
  Swift(macosx-x86_64) :: fail-added-fine.swift
  Swift(macosx-x86_64) :: fail-chained-fine.swift
  Swift(macosx-x86_64) :: fail-interface-hash-fine.swift
  Swift(macosx-x86_64) :: fail-new-fine.swift
  Swift(macosx-x86_64) :: fail-simple-fine.swift
  Swift(macosx-x86_64) :: fail-with-bad-deps-fine.swift
  Swift(macosx-x86_64) :: file-added-fine.swift
  Swift(macosx-x86_64) :: independent-fine.swift
  Swift(macosx-x86_64) :: independent-half-dirty-fine.swift
  Swift(macosx-x86_64) :: independent-parseable-fine.swift
  Swift(macosx-x86_64) :: malformed-but-valid-yaml-fine.swift
  Swift(macosx-x86_64) :: malformed-fine.swift
  Swift(macosx-x86_64) :: mutual-fine.swift
  Swift(macosx-x86_64) :: mutual-interface-hash-fine.swift
  Swift(macosx-x86_64) :: nominal-members-fine.swift
  Swift(macosx-x86_64) :: one-way-depends-after-fine.swift
  Swift(macosx-x86_64) :: one-way-depends-before-fine.swift
  Swift(macosx-x86_64) :: one-way-external-delete-fine.swift
  Swift(macosx-x86_64) :: one-way-external-fine.swift
  Swift(macosx-x86_64) :: one-way-fine.swift
  Swift(macosx-x86_64) :: one-way-merge-module-fine.swift
  Swift(macosx-x86_64) :: one-way-parallel-fine.swift
  Swift(macosx-x86_64) :: one-way-parseable-fine.swift
  Swift(macosx-x86_64) :: one-way-provides-after-fine.swift
  Swift(macosx-x86_64) :: one-way-provides-before-fine.swift
  Swift(macosx-x86_64) :: one-way-while-editing-fine.swift
  Swift(macosx-x86_64) :: only-skip-once.swift
  Swift(macosx-x86_64) :: private-after-fine.swift
  Swift(macosx-x86_64) :: private-fine.swift
  Swift(macosx-x86_64) :: whole-module-build-record.swift

@lorentey
Copy link
Member Author

@swift-ci clean test macOS platform

@lorentey lorentey merged commit 0704746 into swiftlang:main Feb 22, 2022
@lorentey lorentey deleted the unconditional-debugPrecondition branch February 22, 2022 04:59
lorentey added a commit to lorentey/swift that referenced this pull request May 7, 2022
…set a trap function in the stdlib

(The underlying functionality was added in swiftlang#41445 and swiftlang#41449, respectively.)
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.

2 participants