Skip to content

[FreeBSD][SR-3635] Fix __gnustep_objcxx_personality_v0 symbol emitted #12510

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

Closed
wants to merge 1 commit into from
Closed

Conversation

antonmes
Copy link
Contributor

@antonmes antonmes commented Oct 19, 2017

This PR fixes __gnustep_objcxx_personality_v0 symbol being emitted:
libswiftCore.so: undefined reference to __gnustep_objcxx_personality_v0

Related issues: #4804 (comment)

Resolves SR-3635.

@@ -348,7 +348,7 @@ function(_add_variant_link_flags)
if("${LFLAGS_SDK}" STREQUAL "LINUX")
list(APPEND result "-lpthread" "-latomic" "-ldl")
elseif("${LFLAGS_SDK}" STREQUAL "FREEBSD")
list(APPEND result "-lpthread")
list(APPEND result "-lpthread" "-L/usr/local/lib" "-lobjc")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is quite right. We shouldn't really link objC on platforms where interoperability is disabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, i'm trying to remove this dependency, couldn't solve this with any know flags/options, the only working solution i found is to completely avoid .mm. Couldn't we use -lobjc as a temporary fix? Isn't it required on any freebsd platform using the current build environment? Sorry, i'm not familiar with FreeBSD, just having fun 😊

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the correct solution is that of not emitting __gnustep_objcxx_personality_v0 altogether. FWIW, I think clang is the right place to look at (but @jrose-apple / @compnerd probably know better). FWIW, I and @compnerd discussed about enabling obj-C interop on other platforms yesterday. Maybe we can consider taking a look at that on FreeBSD.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should get a working non-ObjC build working on FreeBSD first. Getting ObjC interop on a non-Apple platform will be complicated.

@@ -72,6 +72,13 @@ static SectionInfo getSectionInfo(const char *imageName,
SectionInfo sectionInfo = { 0, nullptr };
void *handle = dlopen(imageName, RTLD_LAZY | RTLD_NOLOAD);
if (!handle) {
#ifdef __FreeBSD__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this bit is fine although it duplicates the logic. Can you try to share the code between FreeBSD and android?

@antonmes
Copy link
Contributor Author

antonmes commented Oct 19, 2017

I found that in swift 3.0 there were *Native.cpp wrappers for Reflection.mm and SwiftValue.mm https://github.com/apple/swift/tree/swift-3.0-branch/stdlib/public/runtime
So bringing them back should solve the issue. Shall I restore them?

Update: found where they were removed #5942

@gparker42
Copy link
Contributor

How is the .mm problem solved on Linux? Is there something in the build system that knows to compile .mm files as C++ on that platform?

@dcci
Copy link
Member

dcci commented Oct 19, 2017

I think you may want instead check what emits that symbol in clang/swift (and why that symbol is emitted). You can probably start running a object file dumper (objdump or readelf) on the file to find out which relocatable ELF objects contain the symbol. Then you can just grab the invocation that produces that object and stare at the intermediate (or just run the compiler under a debugger). It may be tedious but it shouldn't be impossible to track down, IMHO. If you get stuck, let me know.

@@ -1100,6 +1100,7 @@ static Mirror ObjC_getMirrorForSuperclass(Class sup,
//// define what these will be.
/// \returns the demangled name. Returns nullptr if the input String is not a
/// Swift mangled name.
#ifndef __FreeBSD__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the rationale behind this change? As far as I can tell you only commented out the demangler API. Thanks for your hard work, btw!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! It took enormous amount of time to locate this piece of code. I found that both strdup and _swift_strlcpy in this function results to objc being linked. As far as I understood from the comment it's not used anywhere directly. I will file a bug on jira.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that it's not the functions themselves but the combination with std:string, see my comment in the PR thread.

@compnerd
Copy link
Member

Undefined references to __gnustep_personality_v0 is slightly worrisome. That implies that you are using the GNUStep runtime for the ObjC interop. Is the object layout compatible? Right now the swift ObjC interop assumes the resilient NeXTstep layout.

@antonmes
Copy link
Contributor Author

antonmes commented Oct 20, 2017

That's weird, __gnustep_objcxx_personality_v0 emitted if both std::string and strdup/_swift_strlcpy are used in the swift_demangle function even though they are not connected. I don't know what causes this behavior.

SWIFT_RUNTIME_EXPORT
char *swift_demangle(const char *mangledName,
                     size_t mangledNameLength,
                     char *outputBuffer,
                     size_t *outputBufferSize,
                     uint32_t flags) {
  // __gnustep_objcxx_personality_v0
  auto result = std::string();
  return strdup("");

  // ok
  auto result = std::string();
  return ""

  // ok
  return strdup("");
}

Since it's not a part of reflection i suggest we move it to Demangle.cpp, this should solve the issue.

@@ -3448,7 +3448,7 @@ function build_and_test_installable_package() {
call tar -c -z -f "${package_for_host}" "${TOOLCHAIN_PREFIX/#\/}"
else
# tar on OS X doesn't support --owner/--group.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: please change this comment too! It sounds like the real condition here is "BSD tar".

@dcci
Copy link
Member

dcci commented Oct 20, 2017

FWIW, I think you can probably split this in multiple pull requests and rebase.
I think your fixes to 1, 3 and 4 make sense [and I reviewed/tested them], but I still have hard time convincing myself that the undefined Obj-C symbol issue is solved properly.
As I don't want this to be blocked forever, you can probably move the other fixes and we can keep discussing here.

@antonmes
Copy link
Contributor Author

@dcci yeah, there definitely is a bug somewhere in the compiler, and by moving the code we're only avoiding it, but on the other side isn't swift_demangle really belongs to Demangle.cpp?

you mean move fixes 1,2,4 to another PR? _atomics in a number 2.

@dcci
Copy link
Member

dcci commented Oct 20, 2017

I mean everything but the Obj-C issue.

Resolves https://bugs.swift.org/browse/SR-3635

std::string + strdup being used in the function causes some weird behavior
on FreeBSD where __gnustep_objcxx_personality_v0 is emmitted.
It's not happening if the code is in a .cpp file.
@antonmes antonmes changed the title Fix FreeBSD build [FreeBSD][SR-3635] Fix __gnustep_objcxx_personality_v0 symbol emitted Oct 20, 2017
@antonmes
Copy link
Contributor Author

moved to #12528

@jrose-apple
Copy link
Contributor

If we really want to future-proof this…can we just make a policy that says "no .m/.mm files on non-Apple platforms"? And then split these files up appropriately?

(And we could take Anton's patch in the mean time, and clean it up later.)

@compnerd
Copy link
Member

@jrose-apple Im not sure that restriction is really needed.

The better way to handle this is to just actually call out the fact that you need a specific ObjC ABI. We can just add -fobjc-runtime=ios to the flag and get the right behavior. @antonmes is getting a reference to __gnustep_objcxx_personality_v0 because on FreeBSD the default runtime is GNUStep, which cannot work. Switching the runtime to a NeXT family would give us __objc_personality_v0.

However, more worrisome is that somehow -fno-exceptions is being dropped. The std::string constructor is getting marked as except, which is causing the compiler to emit a catch clause which requires a personality. Because the file type is ObjC++, it is using the GNU ObjC++ exception personality __gnustep_objcxx_personality_v0 rather than the __objc_personality_v0 which is used for the NeXT family of ObjC runtimes.

@jrose-apple
Copy link
Contributor

No, no. There should be no ObjC dependencies in the non-Darwin runtimes. We need to link to neither __gnustep_objcxx_personality_v0 nor __objc_personality_v0.

The -fexceptions thing may be deliberate, in order to make the Swift runtime slightly more capable in the face of exceptions. But that does seem unnecessary, given that you already can't throw C++ exceptions through Swift stack frames. @gparker42 (or @rjmccall) would have to say for sure.

@compnerd
Copy link
Member

@jrose-apple yes, I agree that there shouldn't be a mandatory objc dependency. I was suggesting that the issue was exceptions rather than the fact that we have .m or .mm sources being used here. We should be able to keep a single path for all the targets, just need to ensure that we don't end up with ObjC runtime dependencies.

@gparker42
Copy link
Contributor

Can we fix this with an appropriately-placed -x c++ on non-ObjC platforms? Or conversely name the files as .cpp and add -x objective-c++ on ObjC platforms?

@compnerd
Copy link
Member

@gparker42, yes, that would work. The question in my mind is why is this path trying to raise an exception? Having exceptions pop up unexpectedly would be bad. Plus, there are code-size considerations.

@gparker42
Copy link
Contributor

Is it trying to raise an exception? The exception personality functions are used by functions that need to catch or unwind exceptions (such as running local destructors). I don't think they are used by the throw points.

@compnerd
Copy link
Member

@gparker42 right. The std::string constructor may raise an exception if built with exceptions. I suspect that the strdup is resolving to std::strdup which if not marked as noexcept would cause an implicit catch for the local destructors. If we are expecting to handle the exceptions in this case, we shouldn't let the exception propagate past this point (in which case, I agree, the -x approach is the best way to handle this).

@dcci
Copy link
Member

dcci commented Oct 27, 2017

@anton with your fixes in (including this one pending), what's the number of failures on FreeBSD x86-64 for swift?

@jckarter
Copy link
Contributor

I don't think there's anything in the runtime that should require building with -fexceptions.

@antonmes
Copy link
Contributor Author

@dcci you mean test failures? I didn't fix/run any tests and we have the same issue with __atomics* there. After I fixed them by linking libclang_rt.builtins here's what I got: Failing Tests (190)

@antonmes
Copy link
Contributor Author

@compnerd is #12702 related to the issue?

Random question: what is the reason of swift_demangle being in Reflection.mm and not in Demangle.cpp?

@jckarter
Copy link
Contributor

I think it'd be great if we can move code that isn't ObjC specific into plain .cpp files. Ideally we wouldn't have any .mm files in the no-ObjC-interop build. Can the ObjC-specific parts of Reflection.mm be broken out?

@dcci
Copy link
Member

dcci commented Nov 16, 2017

@antonmes are you still planning to make these changes? Thanks!

@compnerd
Copy link
Member

So, just to ensure that this is recorded somewhere ...

Currently, there is only one viable ObjC runtime which can interop with swift: the iOS runtime (non-fragile NeXT). If/when the GNUStep becomes a viable runtime, we could expose the runtime via a switch (à la -fobjc-runtime=).

The next thing to realize is that we do not use ObjC exceptions in the runtime, but we may need the personality to provide the cleanup landing pads (anyone up for setting up MS-style exception funclets for EH? 😄) . However, the frontend will simplify the personality to prefer to use the C++ personality if possible (i.e. there are no ObjC exceptions crossing the boundary, which is the restriction that we have). So, at the end of the day, we should only really be seeing references to __gxx_personality_v0 atm even though we are using .mm files.

I think that overall, sharing the code base this way is better since you have a single implementation. The use of the .mm files effectively is meaningless as we do not use the ObjC bits unless we are enabling the ObjC interop, but the rest of the code can be structured appropriately.

@antonmes
Copy link
Contributor Author

@dcci I'd love to, but I'm stuck. The current PR solves the issue but doesn't prevent it in the future.

Ideally we wouldn't have any .mm files in the no-ObjC-interop build.

@jckarter I don't see a way to split them not involving a lot of code duplication, but the previous solution should met this requirement #12510 (comment) even though .mm is still involved in #include <Reflection.mm> in the no-ObjC-interop build.

I could investigate it further (clang / freebsd sources) but I agree that we shouldn't use .mm files in the no-ObjC-interop build in the first place, so I don't think it's worth it. So the proper solutions would be:

  1. split the code into Reflection.cpp and Reflection.mm (beyond my understanding if possible)
  2. bring the ReflectionNative.cpp back and do #include <Reflection.mm> for the no-ObjC build.

Let's bring the *Native wrappers back?

@jckarter
Copy link
Contributor

OK, I looked at the code and largely agree. Reflection.mm is largely legacy we want to get rid of anyway. Explicitly building it as plain C++ should be fine.

@CodaFi
Copy link
Contributor

CodaFi commented Nov 11, 2019

The core of this patch has been addressed by 44d9b2f. I'm going to close this. Please let me know if this was in error.

@CodaFi CodaFi closed this Nov 11, 2019
3405691582 added a commit to 3405691582/swift that referenced this pull request Apr 16, 2020
See swiftlang#12510 and SR-3635 for some context; OpenBSD exhibits the same
problem listed here. Without this, the build fails with an undefined
symbol error for __gnustep_objcxx_personality_v0. Per commentary on the
aforementioned PR, forcing the language to be interpreted as C++ solves
the problem.

There might be something different we can do here to diagnose and fix
this, but this is the simplest solution to get the build working and
enabling this for all C++ files should be tautologous and therefore
harmless.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants