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 <nothingwasdelive...@gmail.com> 
> 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 
>> <swift-users@swift.org> wrote:
>> 
>> Hi Rick,
>> 
>>> On 21 Sep 2017, at 1:03 am, Rick Mann via swift-users 
>>> <swift-users@swift.org> 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
>>> rm...@latencyzero.com
>>> 
>>> 
>>> _______________________________________________
>>> swift-users mailing list
>>> swift-users@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-users
>> 
>> _______________________________________________
>> swift-users mailing list
>> swift-users@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
> 

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

Reply via email to