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