vapor-community / sockets

🔌 Non-blocking TCP socket layer, with event-driven server and client.
MIT License
575 stars 54 forks source link

rare `UnsafeMutablePointer.initializeFrom` error #33

Closed tanner0101 closed 8 years ago

tanner0101 commented 8 years ago
    let _raw: UnsafeMutablePointer<sockaddr_storage>
    var raw: UnsafeMutablePointer<sockaddr> {
        return UnsafeMutablePointer<sockaddr>(_raw)
    }

    init(raw: UnsafeMutablePointer<sockaddr_storage>) {
        let ptr = UnsafeMutablePointer<sockaddr_storage>.init(allocatingCapacity: 1)
        >>>>>> ptr.initializeFrom(raw, count: 1)
        self._raw = ptr
    }

fatal error: UnsafeMutablePointer.initializeFrom non-following overlapping range

This happens every once in a while. I can't reproduce, but putting it here in case anyone finds more information about it.

czechboy0 commented 8 years ago

I have also seen it, I was able to sort-of reproduce by creating a ResolvedInternetAddress multiple times a second. Unfortunately I'm not sure why initializeFrom(...,1) could be causing this. Anyone?

czechboy0 commented 8 years ago

This is what's failing: https://github.com/apple/swift/blob/master/stdlib/public/core/UnsafePointer.swift.gyb#L333

No idea what that means yet, WIP.

czechboy0 commented 8 years ago

AFAICT, it looks like let ptr = UnsafeMutablePointer<sockaddr_storage>.init(allocatingCapacity: 1) is allocating a pointer which is overlapping the source raw pointer. That could mean that the raw pointer is not properly allocated? It can't be the newly allocated ptr, so it must be raw - or it can also be a bug.

Would be great to find a way to reproduce it. Any links/help appreciated.

tanner0101 commented 8 years ago

I can try to reproduce tomorrow. Maybe putting this function in a loop and calling multiple times could trigger it consistently.

atrick commented 8 years ago

Question for you: did you determine the root of the problem? Was it simply a use-after free? If there's a bug in the language implementation I would like to come up with a test case.

czechboy0 commented 8 years ago

@atrick Yeah it was my fault. See the illustrative gist: https://gist.github.com/czechboy0/e3f3ae64b0a0bc5abba77fd61887dc51 and see the twitter conversation: https://twitter.com/czechboy0/status/739564740037496838 for more details.

Basically I cast a pointer of a smaller type to a pointer of a larger type, without explicitly owning the memory of the difference of the two sizes. Then the allocator gave that free memory to the new pointer and sometimes they overlapped, thus triggering this precondition. Completely my fault and now it's fixed, I explicitly allocate enough space for a full sockaddr_storage beforehand, thus never accidentally capturing deallocated memory even for large address types.

Fixed in 0.4.1