-
-
Notifications
You must be signed in to change notification settings - Fork 262
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
Non matching mangled name for C functions using structs #2782
Comments
This is a duplicate of long-standing #1020. A quick look at the IR shows the problem - 2 equivalent ; ldc2 -output-ll main.d
%main.Foo = type { i32 }
declare void @bar(%main.Foo) #0
; ldc2 -output-ll foo.d
%foo.Foo = type { i32 }
declare void @bar(%foo.Foo) #0 This is We make sure the IR types match if there are multiple declarations (and only emit the first definition in that case). If we didn't, we'd have to adapt the call sites, e.g., repainting IR |
Wouldn't the proper way to do this be to not look at the actual name of the struct but instead its members? Basically building up a mangled/IR name combining the mangled names of the members, recursively. |
That's definitely something I haven't thought of before, but only imagining the length of some of these names (need to take alignments into account as well, unions...) makes my head ache. I look at IR a lot, and having type names >1k isn't bearable IMO. |
Yeah, the might be a problem. But as I mentioned in the other issue #1020 it's easy to detect if a class/struct is |
That has just been added with 2.081 AFAIK. But as your example shows, people don't expect having to declare a struct We could keep a map of struct identifier (excl. module prefix) to IR types, per IR module. When trying to emit a new IR type, we could check if its IR layout is equivalent to an existing type with the same identifier, and use that existing one instead. |
It's been present in
True.
As long it works I'm happy. |
This only applies to C functions, right? For C++ functions, the type is part of the mangling: in the OP example when declare void @bar({i32}) #0 |
C++ functions are affected too, the struct doesn't even need to be |
Doesn't have the same problem as I suggested #2782 (comment)? |
Wow indeed. That's a bad problem that will lead to miscompiles when templates are involved: consider two template instantiations in different compilation units but with different types, they will mangled the same although the types are different and just happen to have the same name, and linking will merge the symbols because that's needed for templates. This sounds like a bug to me: the mangling of C++ functions with D types should use the D type mangling. Simple example that shows the bug: static import core.thread;
struct Thread {
int a;
}
extern (C++) void bar(Thread*) {}
extern (C++) void bar(core.thread.Thread) {} |
I don't necessarily see that as bug, just one more thing to consider for C++ interop. 'Fixing' it would break a ton of code I guess. Our error for mismatching IR signatures may help in preventing such bugs (mainly with Anyway, wrt. to the original issue, I'm not sure a special handling (collapsing types etc.) pays off; after all, this is almost always triggered by duplicate equivalent struct definitions and function declarations, and code duplication is smelly. Extracting the duplicate C[++] types/functions into a dedicated D module solves the problem. |
If we want to allow this (signatures incompatible on the D level), I'd probably go for implementing it using repainting ( We could then have a D-type-system implementation of structural type comparison/whatever heuristics we want to come up with to decide whether to present the user with an error message or not. |
Agreed, but what if two separate D libraries used in a large project wrap the same C/C++ code? |
If compiled in separate invokations (and no LTO), there's no problem. - But yeah, there'll always be some legitimate corner cases (template instantiations...). |
Yeah, repainting the function pointer instead of the args should be a lot simpler indeed. |
I ran in this today as well:
this breaks xlsxd builds. this is with ldc 1.15.0 the structs are different though. |
So xlsxd is duplicating the |
because I use dpp to include the headers of a c library called libxlsxwriter which in turn pulls in stdio.h which pulls in _IO_FILE. another problem I see is that the _IO_FILE in druntine is out-of-date with the one in glibc. |
Ah, yeah dpp doesn't work (at all?) with LDC due to its architecture and this issue - it causes lots of duplicate aggregate definitions (and so init symbol + TypeInfos bloat etc.), Atila knows about it. |
luckily for me, for xlsxd its only _IO_FILE. Commenting that out makes it compile and pass the tests. Has then been any idea/progress been made on this issue in general? |
No progress, but there are some ideas, mainly in this issue here (see #3021 (comment) for links to the other duplicate issues). It's not trivial, and the most promising idea (casting the function pointer after verifying that the signatures are basically equivalent, i.e., that the used aggregates are 'equivalent', although distinct separate types) wouldn't work in your case, as your _IO_FILE diverges from druntime's. |
Yes, use DStep 😉 |
Why not have a sort of @TolerantMangling flag in the meantime so we can get around library conflicts |
Sure, we can implement that as an attribute. I wonder whether that's worth it, though, or whether we should just allow it outright for simplicity (possibly with a warning hidden behind a command-line flag). |
As I've mentioned in #3318 (comment) it would be important to be able to override wrong declarations as well for legacy purposes. |
+1 for the optional warning without extra UDA. Casting the function pointer should implicitly allow slightly wrong declarations, such as int/long for x64 targets if passed in a register. |
I would rather not have warnings that can't be removed if my code is superior to the one it's overriding |
Those warnings would be almost exclusively caused by duplicate struct declarations in multiple analyzed modules, so any 'superiority' would come with TypeInfos bloat (at best, just more stripping work for the linker). Settling for exactly one central D binding, either in druntime or some dub package, for each C(++) library would prevent this issue (and enforce DRY), but that's probably utopic. |
Exactly, but the issue with type bloat is doomed to stay because of workarounds on top of workarounds due to compatibility reasons. If we had the perfect solution from the start it would've helped |
(Only) when compiling them all-at-once anyway; primarily for implicit cross- module inlining across the same library. This won't work as long as there are multiple conflicting declarations across a library's modules - issue ldc-developers#2782.
(Only) when compiling them all-at-once anyway; primarily for implicit cross- module inlining across the same library. This won't work as long as there are multiple conflicting declarations across a library's modules - issue ldc-developers#2782.
this also affects importC: # make the C file - this can be stdio.h or some real header that includes it
cpp -std=c11 -D__restrict= -D__asm__\(x\)= /usr/include/stdio.h > cmodule.c // run: ldc2 -i example.d
// or: ldc2 example.d cmodule.c
import core.stdc.stdio;
static import cmodule;
void main() { fprintf(stdout, "hello\n"); }
(the existence of |
Instead of eagerly IR-declaring all such functions in root modules being compiled. This might reduce compile times in some cases, and is a cheap way to improve the situation wrt. issue ldc-developers#2782.
Instead of eagerly IR-declaring all such functions in root modules being compiled. This might reduce compile times in some cases, and is a cheap way to improve the situation wrt. issue #2782.
The check is now less pedantic - an object file now needs to actually reference multiple conflicting functions (e.g., calling them), for the error to be emitted. |
Instead of eagerly IR-declaring all such functions in root modules being compiled. This might reduce compile times in some cases, and is a cheap way to improve the situation wrt. issue ldc-developers#2782.
Example:
C functions doesn't have a mangling. I suspect the mangled name that would be used for a D function for the
Foo
struct is used.The text was updated successfully, but these errors were encountered: