-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
C++/CLI x86 marshalling misses copy ctor/dtor calls resulting in C++ STL iterator debugging breaking #100033
Comments
For reference, this behavior has been since .NET Core 3.1 since the introduction of C++/CLI support: dotnet/coreclr#22805 |
As we now know, there is a breaking change in dotnet/coreclr#22805. This can be observed with a type that escapes the The change was caused by a removal of machinery that injected additional copy-constructor/destructor calls in locations unrepresentable in IL (ie in the middle of a call instruction and in the unmanaged->managed stub). This is only observable in x86 (other platforms have a different calling convention), and the most likely scenario where this pops up (STL iterators) is only observable with Since removing this logic, we have removed a significant amount of the machinery that supported these features, to the point that restoring the prior machinery (especially in the unmanaged->managed scenario) is not possible. We would need to implement a new approach integrated into the JIT to add support for this scenario. Below is a minimal repro of the code-patterns that can observe the breaking change: #pragma unmanaged
#include <vector>
#include <iostream>
struct Relative;
std::vector<Relative*> relatives;
struct Relative
{
void* relative;
Relative()
{
std::cout << "Registering " << std::hex << this << "\n";
relatives.push_back(this); // Escaping this
relative = this - 1; // Relative pointer stored in object
}
Relative(const Relative& other)
{
std::cout << "Registering copy of " << std::hex << &other << " at " << this << "\n";
relatives.push_back(this); // Escaping this
relative = this - 1; // Relative pointer stored in object
}
~Relative()
{
auto location = std::find(relatives.begin(), relatives.end(), this); // Find escaped this
if (location != relatives.end())
{
std::cout << "Unregistering " << std::hex << this << "\n";
relatives.erase(location);
}
else
{
std::cout << "Error: Relative object " << std::hex << this << " not registered\n";
}
if (relative != this - 1) // Checking relative pointer
{
std::cout << " Error: Relative object " << std::hex << this << " has invalid relative pointer " << std::hex << relative << "\n";
}
}
};
void UseRelative(Relative rel)
{
std::cout << "Unmanaged: Using relative at address " << std::hex << &rel << "\n";
}
void UseRelativeManaged(Relative rel);
void CallRelative()
{
Relative rel;
UseRelativeManaged(rel);
}
#pragma managed
extern "C" void __declspec(dllexport) Run()
{
// Managed to unmanaged
{
Relative rel;
UseRelative(rel);
}
// Unmanaged to managed
CallRelative();
}
void UseRelativeManaged(Relative rel)
{
std::cout << "Managed: Using relative at address " << std::hex << &rel << "\n";
}
Output:
I'm looking into costing what a new approach to fixing this would be. |
This is still fixed as per #100050 |
Description
This issue is a mirror of DTS bug 1949402, meant to track it on Github.
@jkoritzinsky is looking at this issue.
Reproduction Steps
The DTS bug contains the repro. Essentially, a copy ctor of
std::vector<>::iterator
is not called when pushing the argument onto the stack for the call to the native method, which takes an argument of typeiterator
. This leads to STL's iterator debugging book-keeping code to later assert.This happens only for x86 and does not repro in the desktop framework where the copy ctor is correctly called.
Expected behavior
The copy ctor is correctly called and no assert fails in STL iterator debugging code.
Actual behavior
STL iterator debugging assert popup.
Regression?
Yes. From desktop framework behavior. Customer is blocked from adopting Net 8.0
Known Workarounds
Disabling iterator debugging. But this still leaves open the question of silent bad codegen happening for similar code that is not protected by asserts.
Configuration
.NET 8 x86
Other information
No response
The text was updated successfully, but these errors were encountered: