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-2462] Compiler is sometimes overreleasing CF objects #45067

Closed
spevans opened this issue Aug 23, 2016 · 3 comments
Closed

[SR-2462] Compiler is sometimes overreleasing CF objects #45067

spevans opened this issue Aug 23, 2016 · 3 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@spevans
Copy link
Collaborator

spevans commented Aug 23, 2016

Previous ID SR-2462
Radar rdar://problem/27970214
Original Reporter @spevans
Type Bug
Status Closed
Resolution Cannot Reproduce

Attachment: Download

Environment

This is on linux but I have seen the same issue on Darwin as well

Swift version 3.0-dev (LLVM 17c4c6cf7a, Clang 4ca9e01a7c, Swift 7a0ba75)
Target: x86_64-unknown-linux-gnu

swift-corelibs-foundation: 66fad9f

Additional Detail from JIRA
Votes 1
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: a5c7bc4b60607dd23f9b56699626d161

relates to:

  • SR-2707 Swift 3.0 Release Run time Crash With Date/NSDate function
  • SR-2485 Segmentation fault in Date
  • SR-2879 Creating 4 calendars results in an assertion failure

Issue Description:

When calling CoreFoundation functions the swift compiler inserts rt_swift_release calls to release any objects it has gained ownership of. However sometimes it releases objects incorrectly causing the object to be freed early when it shouldnt be. The attached cftest.swift demonstrates this

import Foundation
import CoreFoundation

public func testCFString() {
  let asciiBytes = Data(bytes: [0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x53, 0x77, 0x69, 0x66, 0x74, 0x21, 0x00])
  let str = asciiBytes.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> CFString in 
    CFStringCreateWithCString(kCFAllocatorSystemDefault, bytes, UInt32(kCFStringEncodingASCII))
  }
  print(str)
  CFHash(str)
  CFHash(str)
  CFHash(str)
  CFHash(str)
  CFHash(str)
}


public func testCFTimezone() {  
  let tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0)
  print(tz)
  CFHash(tz)
  CFHash(tz)
  CFHash(tz)
  CFHash(tz)
  CFHash(tz)
}


testCFString()
testCFTimezone()
print("Finished")

running it gives:

Hello Swift!
Optional(<CFTimeZone 0xb4aad0 [0x7f80de59d500]>{name = GMT; abbreviation = GMT; GMT offset = 0; is DST = false})
Segmentation fault

I have attached an disassembly of the two functions, the extra calls after each call to CFHash() can be seen here

<cftest.testCFTimezone () -> ()>:
.
.
401da4:       e8 37 f8 ff ff          callq  4015e0 <Swift.print ([Any], separator : Swift.String, terminator : Swift.String) -> ()@plt>
  401da9:       4c 89 e7                mov    %r12,%rdi
  401dac:       e8 7f f8 ff ff          callq  401630 <CFHash@plt>
  401db1:       4c 89 e7                mov    %r12,%rdi
  401db4:       e8 57 04 00 00          callq  402210 <rt_swift_release>
  401db9:       4c 89 e7                mov    %r12,%rdi
  401dbc:       e8 6f f8 ff ff          callq  401630 <CFHash@plt>
  401dc1:       4c 89 e7                mov    %r12,%rdi
  401dc4:       e8 47 04 00 00          callq  402210 <rt_swift_release>
  401dc9:       4c 89 e7                mov    %r12,%rdi
  401dcc:       e8 5f f8 ff ff          callq  401630 <CFHash@plt>
  401dd1:       4c 89 e7                mov    %r12,%rdi
  401dd4:       e8 37 04 00 00          callq  402210 <rt_swift_release>
  401dd9:       4c 89 e7                mov    %r12,%rdi
  401ddc:       e8 4f f8 ff ff          callq  401630 <CFHash@plt>
  401de1:       4c 89 e7                mov    %r12,%rdi
  401de4:       e8 27 04 00 00          callq  402210 <rt_swift_release>
  401de9:       4c 89 e7                mov    %r12,%rdi
  401dec:       e8 3f f8 ff ff          callq  401630 <CFHash@plt>
  401df1:       be 02 00 00 00          mov    $0x2,%esi
  401df6:       4c 89 e7                mov    %r12,%rdi

compared to:

<cftest.testCFString () -> ()>:
.
.
 401b9c:       e8 3f fa ff ff          callq  4015e0 <Swift.print ([Any], separator : Swift.String, terminator : Swift.String) -> ()@plt>
  401ba1:       4c 89 e7                mov    %r12,%rdi
  401ba4:       e8 87 fa ff ff          callq  401630 <CFHash@plt>
  401ba9:       4c 89 e7                mov    %r12,%rdi
  401bac:       e8 7f fa ff ff          callq  401630 <CFHash@plt>
  401bb1:       4c 89 e7                mov    %r12,%rdi
  401bb4:       e8 77 fa ff ff          callq  401630 <CFHash@plt>
  401bb9:       4c 89 e7                mov    %r12,%rdi
  401bbc:       e8 6f fa ff ff          callq  401630 <CFHash@plt>
  401bc1:       4c 89 e7                mov    %r12,%rdi
  401bc4:       e8 67 fa ff ff          callq  401630 <CFHash@plt>
  401bc9:       4c 89 e7                mov    %r12,%rdi
  401bcc:       e8 3f 06 00 00          callq  402210 <rt_swift_release>
  401bd1:       48 8b 7d c0             mov    -0x40(%rbp),%rdi
  401bd5:       e8 36 06 00 00          callq  402210 <rt_swift_release>

which has just the one release to balance the CFStringCreateWithCString() ownership

@spevans
Copy link
Collaborator Author

spevans commented Sep 2, 2016

I have had another look into this and the extra release only seems to occur when a `let' constant is passed to a CF function taking a CFTypeRef![](. In this case the CFUUID) is cast to an IUO<AnyObject> and it is this cast that its being released. I have attached the SIL as it should make it clearer what is going on.

If the result from CFUUIDCreate() is a `var', is not assigned, is assigned via optional binding or cast directly to a CFUUID then the extra release does not occur. cftest2.swift shows these variants, only testWithLet() does the extra release

The relevant bit from cftest2.sil :

  %2 = apply %0(%1) : $@convention(c) (ImplicitlyUnwrappedOptional<CFAllocator>) -> @owned ImplicitlyUnwrappedOptional<CFUUID>, loc "cftest2.swift":11:27, scope 3 // users: %16, %3
  %3 = unchecked_ref_cast %2 : $ImplicitlyUnwrappedOptional<CFUUID> to $Optional<CFUUID>, loc "cftest2.swift":11:11, scope 3 // users: %5, %6, %4
  debug_value %3 : $Optional<CFUUID>, let, name "x", loc "cftest2.swift":11:7, scope 3 // id: %4
  switch_enum %3 : $Optional<CFUUID>, case #Optional.some!enumelt.1: bb1, case #Optional.none!enumelt: bb2, loc "cftest2.swift":12:10, scope 3 // id: %5

bb1:                                              // Preds: bb0
  %6 = unchecked_enum_data %3 : $Optional<CFUUID>, #Optional.some!enumelt.1, loc "cftest2.swift":12:10, scope 3 // user: %7
  %7 = init_existential_ref %6 : $CFUUID : $CFUUID, $AnyObject, loc "cftest2.swift":12:10, scope 3 // user: %8
  %8 = enum $ImplicitlyUnwrappedOptional<AnyObject>, #ImplicitlyUnwrappedOptional.some!enumelt.1, %7 : $AnyObject, loc "cftest2.swift":12:10, scope 3 // user: %9
  br bb3(%8 : $ImplicitlyUnwrappedOptional<AnyObject>), loc "cftest2.swift":12:10, scope 3 // id: %9

bb2:                                              // Preds: bb0
  %10 = enum $ImplicitlyUnwrappedOptional<AnyObject>, #ImplicitlyUnwrappedOptional.none!enumelt, loc "cftest2.swift":12:10, scope 3 // user: %11
  br bb3(%10 : $ImplicitlyUnwrappedOptional<AnyObject>), loc "cftest2.swift":12:10, scope 3 // id: %11

// %12                                            // users: %15, %14
bb3(%12 : $ImplicitlyUnwrappedOptional<AnyObject>): // Preds: bb2 bb1
  // function_ref CFHash
  %13 = function_ref @CFHash : $@convention(c) (ImplicitlyUnwrappedOptional<AnyObject>) -> UInt, loc "cftest2.swift":12:3, scope 3 // user: %14
  %14 = apply %13(%12) : $@convention(c) (ImplicitlyUnwrappedOptional<AnyObject>) -> UInt, loc "cftest2.swift":12:11, scope 3
  release_value %12 : $ImplicitlyUnwrappedOptional<AnyObject>, scope 2 // id: %15
  release_value %2 : $ImplicitlyUnwrappedOptional<CFUUID>, scope 2 // id: %16

The release_value %12 is the incorrect extra release

@parkera
Copy link
Member

parkera commented Mar 3, 2017

It is reported in apple/swift-corelibs-foundation#898 that this may be fixed on master now.

@spevans
Copy link
Collaborator Author

spevans commented Apr 12, 2017

After retesting this now appears to be fixed in master as I can not reproduce it anymore

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
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. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

2 participants