Hi Chris,
Yes, he'll need to do
withUnsafeMutablePointer(to: &inReq.imageInfo.transformation) {
transformationTuplePtr in
withUnsafeMutablePointer(to: &inReq.imageInfo.projection) {
projectionTuplePtr in
transformationTuplePtr.withMemoryRebound(to: Float.self, capacity: 16) {
transformationArrayPtr in
projectionTuplePtr.withMemoryRebound(to: Float.self, capacity: 16) {
projectionArrayPtr in
....imageReceived(..., transform: transformationArrayPtr,
projection: projectionArrayPtr, ...)
}
}
}
}
if you need access to 5 of them, you'll need to nest deeper, apologies.
However, there's talk on swift-evolution about getting fixed-size arrays into
Swift which would help here. But there's no full proposal yet AFAIK.
-- Johannes
> On 21 Sep 2017, at 2:27 pm, Chris McIntyre <[email protected]>
> wrote:
>
> Sorry to jump in here, and maybe I’m missing something obvious, but in your
> example Rick is two levels of closure deep and only has access to one of the
> arrays in his struct. In this case there is another array of floats he needs
> as an argument to his method call. Will he need to go through the same steps,
> going two levels of closure deeper, before he has access to both struct
> members?
>
> This doesn’t seem to scale very well. What about a struct with 5 arrays?
> --
> Chris McIntyre
>
>
>
>
>> On Sep 21, 2017, at 6:05 AM, Johannes Weiß via swift-users
>> <[email protected]> wrote:
>>
>> Hi Rick,
>>
>>> On 21 Sep 2017, at 1:03 am, Rick Mann via swift-users
>>> <[email protected]> wrote:
>>>
>>> I've got Swift code wrapping a C API. One of the C structs the API uses
>>> looks like this:
>>>
>>> typedef struct {
>>> size_t size;
>>> float transformation[16];
>>> float projection[16];
>>> uint32_t width;
>>> uint32_t height;
>>> } image_info_t;
>>>
>>> In Swift, the two array members are 16-tuples of floats. Eventually, the
>>> Swift code calls an Objective-C delegate, passing a tuple to an array:
>>>
>>> self.delegate?
>>> .imageReceived(self,
>>> index: inReq.imageIndex,
>>> data: data,
>>> width: width,
>>> height: height,
>>> transform: &inReq.imageInfo.transformation.0,
>>> projection: &inReq.imageInfo.projection.0)
>>
>> these are illegal. You're getting a pointer to _only_ the first element
>> (&inReq.imageInfo.transformation.0) but the library will then read 16
>> elements from there.
>>
>> Something like this should work (and is legal):
>>
>> withUnsafeMutablePointer(to: &inReq.imageInfo.transformation) {
>> tupleOfFloatsPtr in
>> tupleOfFloatsPtr.withMemoryRebound(to: Float.self, capacity: 16) {
>> arrayOfFloatsPtr in
>> ....imageReceived(..., transform: arrayOfFloatsPtr, ...)
>> }
>> }
>>
>> that's legal because now we're capturing a pointer to the whole tuple and
>> therefore Swift guarantees the memory to be in C standard layout.
>>
>>
>>
>>>
>>> This seems to have been working fine for a long time, but we're running
>>> into a crash in some cases, and so I've been digging into it. I turned on
>>> the address sanitizer, and I consistently get it to trip in some C++ code
>>> that eventually gets called with a float* to that transform tuple.
>>>
>>> Now, in Swift, the values of the tuple look great:
>>>
>>> ▿ 16 elements
>>> - .0 : 0.548282921
>>> - .1 : 0.821425974
>>> - .2 : -0.156990349
>>> - .3 : 0.0
>>> - .4 : -0.277842015
>>> - .5 : 0.00185899995
>>> - .6 : -0.960625231
>>> - .7 : 0.0
>>> - .8 : -0.788789928
>>> - .9 : 0.570312977
>>> - .10 : 0.229245573
>>> - .11 : 0.0
>>> - .12 : 0.0475889929
>>> - .13 : -0.0323969983
>>> - .14 : -0.0113521963
>>> - .15 : 1.0
>>>
>>> I can see this by clicking up the stack a couple frames to the Swift code.
>>> But the Objective-C(++) delegate code, that gets passed a float*, sees this
>>> (BTW, I can't figure out how to get the debugger, Xcode or command line, to
>>> display inTransform as an array of 16 floats). It's clearly not the same
>>> array.
>>>
>>>
>>> (lldb) po inTransform[0]
>>> 0.548282921
>>>
>>> (lldb) po inTransform[1]
>>> 0.0343905278
>>>
>>> (lldb) po inTransform[2]
>>> -0
>>>
>>> (lldb) po inTransform[3]
>>> 0
>>>
>>> (lldb) po inTransform[4]
>>> 0
>>>
>>> (lldb) po inTransform[5]
>>> 0
>>>
>>> (lldb) po inTransform[6]
>>> 95488384
>>>
>>> (lldb) po inTransform[14]
>>> 0.00000000000000000000000000000000000000000000560519386
>>>
>>> (lldb) po inTransform[15]
>>> 0
>>>
>>> The address sanitizer spits out this:
>>>
>>> =================================================================
>>> ==1358==ERROR: AddressSanitizer: stack-buffer-overflow on address
>>> 0x00014d3ea224 at pc 0x000100eb9a84 bp 0x00016fd84bd0 sp 0x00016fd84bc8
>>> READ of size 4 at 0x00014d3ea224 thread T0
>>> #0 0x100eb9a83 in <redacted>::addImage(void const*, int, int, int, float
>>> const*, float const*) (<redacted>:arm64+0x100e41a83)
>>> #1 0x10040b72b in -[<redacted>
>>> imageReceived:index:data:width:height:transform:projection:]
>>> (<redacted>:arm64+0x10039372b)
>>> #2 0x10045d037 in function signature specialization <Arg[0] = Owned To
>>> Guaranteed, Arg[1] = Owned To Guaranteed, Arg[2] = Owned To Guaranteed and
>>> Exploded> of closure #1 () -> () in
>>> <redacted>.imageDownloaded(<redacted>.DownloadImageRequest, index:
>>> Swift.Int) -> () (<redacted>:arm64+0x1003e5037)
>>> #3 0x100442bbb in closure #1 () -> () in
>>> <redacted>.imageDownloaded(<redacted>.DownloadImageRequest, index:
>>> Swift.Int) -> () (<redacted>:arm64+0x1003cabbb)
>>> #4 0x10043e7fb in reabstraction thunk helper from @callee_owned () -> ()
>>> to @callee_unowned @convention(block) () -> ()
>>> (<redacted>:arm64+0x1003c67fb)
>>> #5 0x103ba9d5b in __wrap_dispatch_async_block_invoke
>>> (/var/containers/Bundle/Application/B3E557CA-5ED9-4673-8B07-37A0F2DA472B/<redacted>.app/Frameworks/libclang_rt.asan_ios_dynamic.dylib:arm64+0x4dd5b)
>>> #6 0x105f1549b in _dispatch_call_block_and_release
>>> (/usr/lib/system/introspection/libdispatch.dylib:arm64+0x149b)
>>> #7 0x105f1545b in _dispatch_client_callout
>>> (/usr/lib/system/introspection/libdispatch.dylib:arm64+0x145b)
>>> #8 0x105f1a04f in _dispatch_main_queue_callback_4CF
>>> (/usr/lib/system/introspection/libdispatch.dylib:arm64+0x604f)
>>> #9 0x181d43f1f in <redacted>
>>> (/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation:arm64+0xe9f1f)
>>> #10 0x181d41afb in <redacted>
>>> (/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation:arm64+0xe7afb)
>>> #11 0x181c622d7 in CFRunLoopRunSpecific
>>> (/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation:arm64+0x82d7)
>>> #12 0x183af3f83 in GSEventRunModal
>>> (/System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices:arm64+0xaf83)
>>> #13 0x18b20e87f in UIApplicationMain
>>> (/System/Library/Frameworks/UIKit.framework/UIKit:arm64+0x7387f)
>>> #14 0x100122dc3 in main (<redacted>:arm64+0x1000aadc3)
>>> #15 0x18178656b in <redacted> (/usr/lib/system/libdyld.dylib:arm64+0x156b)
>>>
>>> Address 0x00014d3ea224 is located in stack of thread T0 at offset 36 in
>>> frame
>>> #0 0x10045cd57 in function signature specialization <Arg[0] = Owned To
>>> Guaranteed, Arg[1] = Owned To Guaranteed, Arg[2] = Owned To Guaranteed and
>>> Exploded> of closure #1 () -> () in
>>> <redacted>.imageDownloaded(<redacted>.DownloadImageRequest, index:
>>> Swift.Int) -> () (<redacted>:arm64+0x1003e4d57)
>>>
>>> This frame has 4 object(s):
>>> [32, 36) '' <== Memory access at offset 36 overflows this variable
>>> [48, 208) ''
>>> [272, 276) ''
>>> [288, 448) ''
>>> HINT: this may be a false positive if your program uses some custom stack
>>> unwind mechanism or swapcontext
>>> (longjmp and C++ exceptions *are* supported)
>>> SUMMARY: AddressSanitizer: stack-buffer-overflow
>>> (<redacted>:arm64+0x100e41a83) in <redacted>::addImage(void const*, int,
>>> int, int, float const*, float const*)
>>> Shadow bytes around the buggy address:
>>> 0x0001302dd3f0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>>> 0x0001302dd400: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>>> 0x0001302dd410: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>>> 0x0001302dd420: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>>> 0x0001302dd430: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>>> =>0x0001302dd440: f1 f1 f1 f1[04]f2 00 00 00 00 00 00 00 00 00 00
>>> 0x0001302dd450: 00 00 00 00 00 00 00 00 00 00 f2 f2 f2 f2 f2 f2
>>> 0x0001302dd460: f2 f2 04 f2 00 00 00 00 00 00 00 00 00 00 00 00
>>> 0x0001302dd470: 00 00 00 00 00 00 00 00 f3 f3 f3 f3 f3 f3 f3 f3
>>> 0x0001302dd480: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>>> 0x0001302dd490: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
>>> Shadow byte legend (one shadow byte represents 8 application bytes):
>>> Addressable: 00
>>> Partially addressable: 01 02 03 04 05 06 07
>>> Heap left redzone: fa
>>> Freed heap region: fd
>>> Stack left redzone: f1
>>> Stack mid redzone: f2
>>> Stack right redzone: f3
>>> Stack after return: f5
>>> Stack use after scope: f8
>>> Global redzone: f9
>>> Global init order: f6
>>> Poisoned by user: f7
>>> Container overflow: fc
>>> Array cookie: ac
>>> Intra object redzone: bb
>>> ASan internal: fe
>>> Left alloca redzone: ca
>>> Right alloca redzone: cb
>>>
>>>
>>>
>>> So, how do I properly go back and forth between C and Swift code with
>>> pointers to arrays of floats?
>>>
>>> Thanks,
>>>
>>> --
>>> Rick Mann
>>> [email protected]
>>>
>>>
>>> _______________________________________________
>>> swift-users mailing list
>>> [email protected]
>>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>> _______________________________________________
>> swift-users mailing list
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-users
>
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users