Skip to content

[stdlib] Avoid malloc_size on OpenBSD. #30560

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

Conversation

3405691582
Copy link
Member

malloc introspection is a platform feature that is unavailable on
OpenBSD. There is no workaround for the feature, so simply avoid calling
it in this case. It is assumed on OpenBSD that the tail allocator will
allocate the amount of memory requested of it, and nothing more.

@3405691582
Copy link
Member Author

cc @milseman who was working in this area recently

Copy link
Contributor

@CodaFi CodaFi left a comment

Choose a reason for hiding this comment

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

Could you please add a comment here explaining what you wrote in the PR's summary?

@milseman
Copy link
Member

Array also calls malloc_size, and has for years. String just recently added this. I'm curious, how did this manifest for you? Is there an alternative we can do in the shim instead?

@milseman
Copy link
Member

CC @Catfish-Man @jckarter

@3405691582 3405691582 force-pushed the OpenBSD_StringStorage_AvoidMallocSize branch from 3886ca2 to 538e2d3 Compare March 27, 2020 23:33
@3405691582
Copy link
Member Author

Could you please add a comment here explaining what you wrote in the PR's summary?

Done. I tweaked the language in the code comment to be a little more generic; who knows if there might be a porting effort by someone to another platform without malloc introspection.

Array also calls malloc_size, and has for years. String just recently added this. I'm curious, how did this manifest for you? Is there an alternative we can do in the shim instead?

There are three uses of malloc_size in Swift that are problematic:

  • ContiguousArrayBuffer.swift -- this is easy to fix, but this looks like it might be partially addressed in pr Adopt the new allocation/growth strategy in Array #30270, so it might just be easiest to wait for that.
  • ManagedBuffer.swift -- this one is more complicated to fix, because the allocation and the introspection call contexts are separated far apart. I have an unpublished commit to kludge around this, but it's a bit of a hack.
  • StringStorage.swift -- this pr.

I'm working on an OpenBSD port recently. It doesn't have malloc introspection, and introspection like this is something we can't kludge around, because knowing the allocation extents depends on introspecting the system allocator, so the only way around this is to track the size of the allocation in parallel with every allocation.

@jckarter
Copy link
Contributor

jckarter commented Mar 30, 2020

It's going to be easy to forget about platforms like OpenBSD as we work on the standard library and refactor code, which might add new malloc_size checks in the future. It might be better for long term maintenance if we wrapped up all of the standard library's uses of malloc_size in a helper function that handles the case that it might be unavailable. We could add a _stdlib_has_malloc_size static inline function to the shims, and implement the helper like this:

internal func mallocSize(ptr: UnsafeRawPointer) -> UInt {
  if _stdlib_has_malloc_size() {
    return _stdlib_malloc_size(ptr)
  }
  return nil
}

_stdlib_malloc_size could then be stubbed out to abort on OSes that don't have it as well.
That way, the conditional only has to be in one place for any OSes that don't support malloc introspection.

@3405691582
Copy link
Member Author

3405691582 commented Mar 30, 2020

I'm happy to try and make that refactor here, that sounds simple and straightforward enough in itself, but I still don't know how to apply it for ManagedBufferPointer. That doesn't mean we can't at least apply that scheme where it works for the moment.

@jckarter
Copy link
Contributor

@Catfish-Man or @milseman would be more familiar with the specific code at hand, but in general, you ought to be able to replace existing direct calls to _stdlib_malloc_size(x) with mallocSize(x) ?? originalMallocArgument, since we should be able to assume we got at least as much memory as we'd asked for originally.

@3405691582
Copy link
Member Author

Sure, but the problem with ManagedBufferPointer is that the malloc_size call is divorced from the allocation (see _capacityInBytes), and ManagedBufferPointer asserts on "illegal stored properties".

Happy to hear further advice on this, though.

@3405691582 3405691582 force-pushed the OpenBSD_StringStorage_AvoidMallocSize branch 2 times, most recently from 09262ff to f594ddb Compare March 31, 2020 03:10
@3405691582
Copy link
Member Author

3405691582 commented Mar 31, 2020

Adopted @jckarter's suggestion to introduce a new shim. Still would like to hear if @Catfish-Man or @milseman have advice.

Points of note:

  • as mentioned, ManagedBuffer.swift is not converted in this PR

  • mallocSize shim returns Optional<Int> and not Optional<UInt>, because the operators on pointers take Ints; the preexisting code also makes some assumptions based on _swift_stdlib_malloc_size returning an Int.

  • the catchall implementation of _swift_stdlib_malloc_size returns 0 instead of asserting; it might make things a little too complex to try and drag in the necessary dependencies to get runtime assertions.

@compnerd
Copy link
Member

compnerd commented Apr 3, 2020

Thanks for this, I think that the shim'ed approach is definitely nicer.

@compnerd
Copy link
Member

compnerd commented Apr 3, 2020

@swift-ci please test

@swift-ci
Copy link
Contributor

swift-ci commented Apr 3, 2020

Build failed
Swift Test Linux Platform
Git Sha - 3886ca245bb8bc5e82b352ed6383963229588347

@swift-ci
Copy link
Contributor

swift-ci commented Apr 3, 2020

Build failed
Swift Test OS X Platform
Git Sha - 3886ca245bb8bc5e82b352ed6383963229588347

@compnerd
Copy link
Member

compnerd commented Apr 8, 2020

@swift-ci please test macOS platform

@swift-ci
Copy link
Contributor

swift-ci commented Apr 8, 2020

Build failed
Swift Test OS X Platform
Git Sha - f594ddb4439c73d53df83918ab95d37c4a463fdd

@3405691582
Copy link
Member Author

Looks like the OS X build failure is because swiftpm is being built with a platform Swift SDK for SDKROOT but with the Swift stdlib from HEAD + this PR, is that right? Is there something this PR is missing?

@CodaFi
Copy link
Contributor

CodaFi commented Apr 13, 2020

Lost the build failure

@swift-ci test macOS platform

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - f594ddb4439c73d53df83918ab95d37c4a463fdd

Copy link
Contributor

@benrimmington benrimmington left a comment

Choose a reason for hiding this comment

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

Suggestions:

  • use __swift_bool if possible?

  • and update the copyright year in all files.

    -// Copyright (c) 2014 - 20** Apple Inc. and the Swift project authors
    +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors

@3405691582 3405691582 force-pushed the OpenBSD_StringStorage_AvoidMallocSize branch from f594ddb to 4b70859 Compare April 15, 2020 04:30
Comment on lines 115 to 118
#define HAS_MALLOC_SIZE 1
static inline __swift_size_t _swift_stdlib_malloc_size(const void *ptr) {
#if defined(__ANDROID__)
#define HAS_MALLOC_SIZE 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this #define HAS_MALLOC_SIZE twice for Android?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, should HAS_MALLOC_SIZE be renamed to _SWIFT_STDLIB_HAS_MALLOC_SIZE?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. Removed the Android #define.

I'm not sure a rename is necessary; giving it a full prefix suggests this is something with stronger scope than it actually has. The underscore prefix seems rather uncommon for stdlib as well, so I'm inclined to leave it as-is.

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: replace each #define HAS_MALLOC_SIZE with a function?

-#define HAS_MALLOC_SIZE 1
+static inline __swift_bool _swift_stdlib_has_malloc_size() { return true; }
-#define HAS_MALLOC_SIZE 0
+static inline __swift_bool _swift_stdlib_has_malloc_size() { return false; }

Copy link
Member Author

Choose a reason for hiding this comment

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

It's a lot more to copy and paste for the next new port, though.This suggests it would be far better to push the preprocessor conditionals into one definition of each function at the top level, but that would probably be better suited to do in a separate PR.

@3405691582 3405691582 force-pushed the OpenBSD_StringStorage_AvoidMallocSize branch from 4b70859 to 03ffde0 Compare April 15, 2020 15:20
@jckarter
Copy link
Contributor

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - f594ddb4439c73d53df83918ab95d37c4a463fdd

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - f594ddb4439c73d53df83918ab95d37c4a463fdd

@compnerd
Copy link
Member

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 03ffde0cecb3c576c500a9de4242ec8e1b3d222b

@compnerd
Copy link
Member

@swift-ci please test macOS platform

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 03ffde0cecb3c576c500a9de4242ec8e1b3d222b

@benrimmington
Copy link
Contributor

The macOS failure was:

dyld: Symbol not found: _$ss11_mallocSize12ofAllocationSiSgSV_tF
  Referenced from: /Users/buildnode/jenkins/workspace/swift-PR-osx/branch-master/buildbot_incremental/swiftpm-macosx-x86_64/x86_64-apple-macosx/release/swift-test
  Expected in: /usr/lib/swift/libswiftCore.dylib

Does this mean that the system dylib is expected to contain the new _mallocSize(ofAllocation:) function, when building SwiftPM?

@compnerd
Copy link
Member

Yes, the tests currently run against the system version of the core library. This is due to a system issue that’s been there for a while. Fixing that is blocked by the other build system work that exposes the issue in an addressable manner.

CC: @drexin

@jckarter
Copy link
Contributor

Running tests against the OS runtime seems like a feature, not a bug, because we want to know if we accidentally add symbols to the standard library, since they'll be burdened by deployment target limitations because they aren't available in older OSes.

In this case, we need to mark that new function with the @_alwaysEmitIntoClient attribute, so that it's not part of the standard library ABI.

@@ -36,3 +36,8 @@ internal var _fastEnumerationStorageMutationsTarget: CUnsignedLong = 0
internal let _fastEnumerationStorageMutationsPtr =
UnsafeMutablePointer<CUnsignedLong>(Builtin.addressof(&_fastEnumerationStorageMutationsTarget))
#endif

@usableFromInline
Copy link
Contributor

Choose a reason for hiding this comment

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

In addition to being @usableFromInline, this should also be @_alwaysEmitIntoClient, so that user code doesn't try to link against a nonexistent symbol in older Swift runtime dylibs.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Thanks, that's the piece of knowledge I was missing here.

malloc introspection is a platform feature that is unavailable on
OpenBSD. There is no workaround for the feature, so we have to assume
that allocations succeed in allocating exactly the amount of memory
requested, and nothing more.

Here a new mallocSize shim is introduced so the feature check for malloc
introspection is pushed to the shims, rather than using os checks
directly from Swift. Not every use of malloc_size has been converted
yet; ManagedBuffer.swift still remains. However, this module requires
special care to fix, which will be done separately.
@3405691582 3405691582 force-pushed the OpenBSD_StringStorage_AvoidMallocSize branch from 03ffde0 to 7830028 Compare April 28, 2020 00:04
@3405691582
Copy link
Member Author

Can someone please kick-off swift-ci on Mac OS for me?

@jckarter
Copy link
Contributor

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 03ffde0cecb3c576c500a9de4242ec8e1b3d222b

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 03ffde0cecb3c576c500a9de4242ec8e1b3d222b

@jckarter
Copy link
Contributor

@CodaFi This look good before I merge?

@jckarter jckarter merged commit 9cdfb0e into swiftlang:master Apr 29, 2020
@jckarter
Copy link
Contributor

Thanks @3405691582!

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.

7 participants