UnsafeMutablePointer<String> vs. UnsafeMutablePointer<Int>


(Adrian Zubarev) #1

I played around with UnsafeMutablePointer and realized one behavior:

let pString = UnsafeMutablePointer<String>.alloc(1)
pString.initialize("test")
pString.predecessor().memory // will crash ax expected
pString.predecessor() == pString.advancedBy(-1) // true
pString.destroy()
pString.dealloc(1)
where

let iInt = UnsafeMutablePointer<String>.alloc(1)
iInt.initialize("test")
iInt.predecessor().memory // will not crash
iInt.predecessor() == iInt.advancedBy(-1) // true
iInt.predecessor().memory = 42 // did I just modified some memory I don't own?
iInt.destroy()
iInt.dealloc(1)
Is this intended? This is really the case where its unsafe.

···

--
Adrian Zubarev
Sent with Airmail


(Dmitri Gribenko) #2

Hi Adrian,

I played around with UnsafeMutablePointer and realized one behavior:

let pString = UnsafeMutablePointer<String>.alloc(1)
pString.initialize("test")
pString.predecessor().memory // will crash ax expected
pString.predecessor() == pString.advancedBy(-1) // true
pString.destroy()
pString.dealloc(1)

where

let iInt = UnsafeMutablePointer<String>.alloc(1)
iInt.initialize("test")
iInt.predecessor().memory // will not crash
iInt.predecessor() == iInt.advancedBy(-1) // true
iInt.predecessor().memory = 42 // did I just modified some memory I don't
own?

Yes, you did.

In the String case the crash is not guaranteed (it is a segmentation
fault, not a controlled trap). Someone else's valid String can happen
to be located immediately before your memory chunk, and then the code
would "just work", loading that other string.

Dereferencing (reading or writing into) an out-of-bounds pointer is
undefined behavior in Swift.

Dmitri

···

On Sat, May 21, 2016 at 1:48 AM, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Adrian Zubarev) #3

So basically if I do something like this I should be on the safe side:

public class Characters {
         
    private let reference: UnsafeMutablePointer<Character>

    var characters: [Character] {
             
        var characters = [Character]()
             
        for index in 0..<self.count {
                 
            characters.append(self.reference.advancedBy(index).memory)
        }
        return characters
    }
         
    var combined: String { return String(self.characters) }
         
    public let count: Int
         
    public init(value: String) {
             
        let characters = value.characters
             
        self.count = characters.count
        self.reference = UnsafeMutablePointer<Character>.alloc(self.count)
        self.reference.initializeFrom(characters)
    }
         
    deinit {
             
        self.reference.destroy(self.count)
        self.reference.dealloc(self.count)
    }
}
Or do I have to fix something?

Here I don’t walk out of the boundary I allocate.

Does the UnsafeMutablePointer reserves me a safe portion of memory (by safe I mean which isn’t used by anyone at the time I will start using it)?

Sure another pointer could be created and hack into my memory but that wasn’t the question. :slight_smile:

Thanks.

···

--
Adrian Zubarev
Sent with Airmail

Am 21. Mai 2016 bei 11:04:10, Dmitri Gribenko (gribozavr@gmail.com) schrieb:

Hi Adrian,

On Sat, May 21, 2016 at 1:48 AM, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

I played around with UnsafeMutablePointer and realized one behavior:

let pString = UnsafeMutablePointer<String>.alloc(1)
pString.initialize("test")
pString.predecessor().memory // will crash ax expected
pString.predecessor() == pString.advancedBy(-1) // true
pString.destroy()
pString.dealloc(1)

where

let iInt = UnsafeMutablePointer<String>.alloc(1)
iInt.initialize("test")
iInt.predecessor().memory // will not crash
iInt.predecessor() == iInt.advancedBy(-1) // true
iInt.predecessor().memory = 42 // did I just modified some memory I don't
own?

Yes, you did.

In the String case the crash is not guaranteed (it is a segmentation
fault, not a controlled trap). Someone else's valid String can happen
to be located immediately before your memory chunk, and then the code
would "just work", loading that other string.

Dereferencing (reading or writing into) an out-of-bounds pointer is
undefined behavior in Swift.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Jordan Rose) #4

Dmitri’s answers are all better for this specific discussion, but in general, “unsafe” in Swift means “if you don’t follow the rules, this may crash, may silently corrupt memory or do other bad things, may cause other code to be optimized out or miscompiled, may be harmless”. In this particular case, it’d be hard to check for the validity of the pointer while also being fast and binary-compatible with C.

Jordan

···

On May 21, 2016, at 01:48, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

I played around with UnsafeMutablePointer and realized one behavior:

let pString = UnsafeMutablePointer<String>.alloc(1)
pString.initialize("test")
pString.predecessor().memory // will crash ax expected
pString.predecessor() == pString.advancedBy(-1) // true
pString.destroy()
pString.dealloc(1)
where

let iInt = UnsafeMutablePointer<String>.alloc(1)
iInt.initialize("test")
iInt.predecessor().memory // will not crash
iInt.predecessor() == iInt.advancedBy(-1) // true
iInt.predecessor().memory = 42 // did I just modified some memory I don't own?
iInt.destroy()
iInt.dealloc(1)
Is this intended? This is really the case where its unsafe.


(Dmitri Gribenko) #5

So basically if I do something like this I should be on the safe side:

Yes, this code is safe. If you just want to store a contiguous buffer
of elements of the same type, you should consider using Array. It has
methods that will allow you to operate on the unsafe pointer to the
memory if you need that for speed, but it will do the memory
management for you.

Does the UnsafeMutablePointer reserves me a safe portion of memory (by safe
I mean which isn’t used by anyone at the time I will start using it)?

Yes, you will become a unique owner of the newly allocated chunk of
memory. (Same as malloc() in C.)

Dmitri

···

On Sat, May 21, 2016 at 2:15 AM, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Adrian Zubarev) #6

I’ve got one more question that bothers me.

Lets say I’ve got a class that might look something like this:

class Reference {
     
    var pointer: UnsafeMutablePointer<Int>
     
    init(integer: Int) {
        self.pointer = UnsafeMutablePointer<Int>.alloc(1)
        self.pointer.initialize(integer)
    }
     
    deinit {
        self.pointer.destroy(1)
        self.pointer.dealloc(1)
    }
}
Let talk about ARC here. If I use optionals here and release manually the reference deinit will be called and we’re happy here:

var reference: Reference? = Reference(integer: 123456789)
reference = nil
If I don’t use optionals because I want my value to exist while the application is running, deinit will never be called but my application terminates just fine (SIGKILL?):

let reference = Reference(integer: 123456789)
Doesn’t this create a memory leak?

How do I solve this problem, especially if don’t know whats inside the Reference type (assume I’m a different developer who only has access to the framework but not its implementation)?

···

--
Adrian Zubarev
Sent with Airmail

Am 23. Mai 2016 um 18:31:43, Jordan Rose (jordan_rose@apple.com) schrieb:

On May 21, 2016, at 01:48, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

I played around with UnsafeMutablePointer and realized one behavior:

let pString = UnsafeMutablePointer<String>.alloc(1)
pString.initialize("test")
pString.predecessor().memory // will crash ax expected
pString.predecessor() == pString.advancedBy(-1) // true
pString.destroy()
pString.dealloc(1)

where

let iInt = UnsafeMutablePointer<String>.alloc(1)
iInt.initialize("test")
iInt.predecessor().memory // will not crash
iInt.predecessor() == iInt.advancedBy(-1) // true
iInt.predecessor().memory = 42 // did I just modified some memory I don't own?
iInt.destroy()
iInt.dealloc(1)

Is this intended? This is really the case where its unsafe.

Dmitri’s answers are all better for this specific discussion, but in general, “unsafe” in Swift means “if you don’t follow the rules, this may crash, may silently corrupt memory or do other bad things, may cause other code to be optimized out or miscompiled, may be harmless”. In this particular case, it’d be hard to check for the validity of the pointer while also being fast and binary-compatible with C.

Jordan


(Austin Zheng) #7

This shouldn't be something you need to worry about. The mechanism the OS uses to handle memory per process is different from the mechanism your process uses to allocate memory, and the OS should reclaim all the memory that your app used (whether it was 'leaked' or not).

More info: http://stackoverflow.com/questions/2975831/is-leaked-memory-freed-up-when-the-program-exits

Best,
Austin

···

On Jun 1, 2016, at 9:13 AM, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

I’ve got one more question that bothers me.

Lets say I’ve got a class that might look something like this:

class Reference {
     
    var pointer: UnsafeMutablePointer<Int>
     
    init(integer: Int) {
        self.pointer = UnsafeMutablePointer<Int>.alloc(1)
        self.pointer.initialize(integer)
    }
     
    deinit {
        self.pointer.destroy(1)
        self.pointer.dealloc(1)
    }
}
Let talk about ARC here. If I use optionals here and release manually the reference deinit will be called and we’re happy here:

var reference: Reference? = Reference(integer: 123456789)
reference = nil
If I don’t use optionals because I want my value to exist while the application is running, deinit will never be called but my application terminates just fine (SIGKILL?):

let reference = Reference(integer: 123456789)
Doesn’t this create a memory leak?

How do I solve this problem, especially if don’t know whats inside the Reference type (assume I’m a different developer who only has access to the framework but not its implementation)?

--
Adrian Zubarev
Sent with Airmail

Am 23. Mai 2016 um 18:31:43, Jordan Rose (jordan_rose@apple.com <mailto:jordan_rose@apple.com>) schrieb:

On May 21, 2016, at 01:48, Adrian Zubarev via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I played around with UnsafeMutablePointer and realized one behavior:

let pString = UnsafeMutablePointer<String>.alloc(1)
pString.initialize("test")
pString.predecessor().memory // will crash ax expected
pString.predecessor() == pString.advancedBy(-1) // true
pString.destroy()
pString.dealloc(1)

where

let iInt = UnsafeMutablePointer<String>.alloc(1)
iInt.initialize("test")
iInt.predecessor().memory // will not crash
iInt.predecessor() == iInt.advancedBy(-1) // true
iInt.predecessor().memory = 42 // did I just modified some memory I don't own?
iInt.destroy()
iInt.dealloc(1)

Is this intended? This is really the case where its unsafe.

Dmitri’s answers are all better for this specific discussion, but in general, “unsafe” in Swift means “if you don’t follow the rules, this may crash, may silently corrupt memory or do other bad things, may cause other code to be optimized out or miscompiled, may be harmless”. In this particular case, it’d be hard to check for the validity of the pointer while also being fast and binary-compatible with C.

Jordan

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Adrian Zubarev) #8

So basically if my application terminates without errors or crashes I can be sure that the OS will free any memory it used.

Now I feel safe using UnsafeMutablePointers in swift :slight_smile:

···

--
Adrian Zubarev
Sent with Airmail

Am 1. Juni 2016 um 18:19:01, Austin Zheng (austinzheng@gmail.com) schrieb:

This shouldn't be something you need to worry about. The mechanism the OS uses to handle memory per process is different from the mechanism your process uses to allocate memory, and the OS should reclaim all the memory that your app used (whether it was 'leaked' or not).

More info: http://stackoverflow.com/questions/2975831/is-leaked-memory-freed-up-when-the-program-exits

Best,
Austin

On Jun 1, 2016, at 9:13 AM, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

I’ve got one more question that bothers me.

Lets say I’ve got a class that might look something like this:

class Reference {
      
    var pointer: UnsafeMutablePointer<Int>
      
    init(integer: Int) {
        self.pointer = UnsafeMutablePointer<Int>.alloc(1)
        self.pointer.initialize(integer)
    }
      
    deinit {
        self.pointer.destroy(1)
        self.pointer.dealloc(1)
    }
}
Let talk about ARC here. If I use optionals here and release manually the reference deinit will be called and we’re happy here:

var reference: Reference? = Reference(integer: 123456789)
reference = nil
If I don’t use optionals because I want my value to exist while the application is running, deinit will never be called but my application terminates just fine (SIGKILL?):

let reference = Reference(integer: 123456789)
Doesn’t this create a memory leak?

How do I solve this problem, especially if don’t know whats inside the Reference type (assume I’m a different developer who only has access to the framework but not its implementation)?

--
Adrian Zubarev
Sent with Airmail

Am 23. Mai 2016 um 18:31:43, Jordan Rose (jordan_rose@apple.com) schrieb:

On May 21, 2016, at 01:48, Adrian Zubarev via swift-users <swift-users@swift.org> wrote:

I played around with UnsafeMutablePointer and realized one behavior:

let pString = UnsafeMutablePointer<String>.alloc(1)
pString.initialize("test")
pString.predecessor().memory // will crash ax expected
pString.predecessor() == pString.advancedBy(-1) // true
pString.destroy()
pString.dealloc(1)

where

let iInt = UnsafeMutablePointer<String>.alloc(1)
iInt.initialize("test")
iInt.predecessor().memory // will not crash
iInt.predecessor() == iInt.advancedBy(-1) // true
iInt.predecessor().memory = 42 // did I just modified some memory I don't own?
iInt.destroy()
iInt.dealloc(1)

Is this intended? This is really the case where its unsafe.

Dmitri’s answers are all better for this specific discussion, but in general, “unsafe” in Swift means “if you don’t follow the rules, this may crash, may silently corrupt memory or do other bad things, may cause other code to be optimized out or miscompiled, may be harmless”. In this particular case, it’d be hard to check for the validity of the pointer while also being fast and binary-compatible with C.

Jordan

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users