New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-7991] [Windows] Dynamic casts cause the executable to crash #50524
Comments
Comment by Dietmar Planitzer (JIRA) I ran the Swift compiler in the MSVC debugger so that I could look at the .obj file that the Swift compiler generates. The Swift metadata sections look good there. Here's the reflection strings section:
and the protocol conformance section:
So it looks like as if something goes wrong when the MSVC linker kicks in and generates the final exe. Linker version:
|
cc @compnerd |
Comment by Dietmar Planitzer (JIRA) Some more observations: Looking at the stdlib/public/runtime/SwiftRT-COFF.cpp it appears that 8 zero bytes at the beginning and end of the sw5* sections are expected:
I do see those 8 zero bytes in the executable that I've built (the simple print("hello world"). But I see way more than 8 zero bytes in the swiftCore.dll and this is why we get the crash. I've changed the definition of the _start##name and _stop#name variables in my local copy so that they store the value 0xDEADBEEF. This is what I see if I rebuild swiftCore.dll and run dumpbin on the sw5rfst section:
So this shows the sw5rfst section after it has been created by merging the sw5rfst$A, sw5rfst$B and sw5rfstr$C input sections. Notice that what was the sw5rfst$A and the sw5rfst$C sections are now followed by 256 0 bytes. It's as if the linker has added 256 extra padding bytes at the end of those guys before it merged everything together. The first 8 bytes are my 0xDEADBEEF and I think that the next 8 0 bytes are there because the sw5rfst$B section declares in its section header that it wants to be 16 byte aligned. I found this stack overflow discussion which mentions that sections may receive 256 byte padding. The last answer there suggests that the padding is only added for debug builds. And indeed swiftCore.dll contains .debug sections so I guess it was built in debug mode. Now assuming that it's indeed the debug mode that causes the insertion of the extra padding bytes, it's not really clear to me what the appropriate fix would be. Whether the Swift runtime needs to be taught to somehow figure out whether the extra padding is there and ignore it or whether it's possible and desirable to build / link debug versions of swiftCore.dll such that it never contains extra padding bytes (I guess that this would be the preferable thing to do). |
Comment by Dietmar Planitzer (JIRA) There's also this interesting comment
in this clang / compiler-rt file. So I guess I'll rebuild everything with /INCREMENTAL:NO and hope that this fixes it. |
Comment by Dietmar Planitzer (JIRA) Making sure that all Swift libraries are linked with /INCREMENTAL:NO fixes this. However it would probably make sense to change the Swift runtime implementation such that it is able to deal with incrementally linked libraries. But the caveat here is that while the beginning of the sw5*$B section is always at alignTo(sizeof(_start_sw5*) + 256, 16), the location of the corresponding __stop_sw5* variable can be much further out than 256 bytes... |
Comment by Dietmar Planitzer (JIRA) Created a PR with a fix for this: Implemented runtime support for MSVC incremental linking. |
Environment
OS: Windows 10
SDK: Windows SDK Version 10.0.17134.0
Visual Studio 2017: v15.7.3
Swift: Swift version 4.2-dev (LLVM 58850e66ae, Clang 8c059b98e4, Swift a22b360)
Swift compiler compiled with a debug version of llvm-clang
Additional Detail from JIRA
md5: a1f3a1f6115e344c8d439ade14da5dce
Issue Description:
Dynamic Swift casts like for example
will crash a Swift program. The simplest way to replicate this is to compile and run this Swift code:
This crashes when the print() function tries to dynamically cast the string to a TextOutputStreamable here:
More specifically the exact crash location is in this code:
because the section which contains the protocol conformance records appears to be incorrectly generated. Here is a dump of the protocol conformance section from swiftCore.dll (which is affected by the same problem):
Notice the 0 bytes at the beginning of the section which as far as I can tell from reading the Swift sources shouldn't be there because the relative pointers for protocol conformance records are supposed to be never NULL. However those 0 bytes cause the Swift runtime to misinterpret the data and eventually it will try to parse one of the relative pointers as the type field of a protocol which then leads the swift_conformsToProtocolImpl() function right off a 1000 meter cliff and to a painful death.
Even the reflection strings section has those weird leading 0 bytes in there:
I've cross-checked with macOS and Linux and I don't see any leading 0 bytes on those systems.
The number of leading 0 bytes appears to be variable. Here is the reflection strings section from a simple Swift app that defines a single struct with two properties:
The text was updated successfully, but these errors were encountered: