STL icon indicating copy to clipboard operation
STL copied to clipboard

Iterator debugging asserts in mixed managed/native code

Open ngoozeff opened this issue 6 years ago • 6 comments

Describe the bug

Iterator debugging fires an assert in xmemory when the sample is built with mixed managed/unmanaged translation units. When everything is compiled as unmanaged the assert does not fire.

The sample involves a std::function passing across managed/unmanaged boundaries with placeholders for the iterators. The assert fires for foo from the managed code, but not bar from the unmanaged code. I would expect it to fire for both or neither.

Command-line test case STL version (git commit or Visual Studio version): 0281a452293b4e9bd2a0b77cdd1a58ac63a9b086

Self contained test case is at:

https://github.com/ngoozeff/iter_test

Open a Visual Studio Command Prompt to the directory containing the checked out code from above, execute the run.cmd command. run2.cmd has some setup helpers for the include paths etc, you would need to adjust to your environment.

Expected behavior Program runs cleanly.

Additional context

Microsoft (R) C/C++ Optimizing Compiler Version 19.23.28105.4 for x64

ngoozeff avatar Sep 26 '19 09:09 ngoozeff

I've reproduced this bug, thanks for the easy to run (and easy to get) reproduction case.

barcharcraz avatar Sep 26 '19 22:09 barcharcraz

I reduced the repro a bit:

// main.cc, native code
#include <vector>

void apply(std::vector<int>::iterator) {}

extern void foo();

int main() {
    foo();
}
// mgd.cc, managed
#include <vector>

extern void apply(std::vector<int>::iterator b);

static_assert(std::_Is_invocable_r<void, void (*)(std::vector<int>::iterator), std::vector<int>::iterator>::value, "");

void foo() {
    std::vector<int> v;
    apply(v.begin());
}

If we comment out the static assert from mgd.cc then the program will run cleanly.

I tested on VS 2022 17.1 Preview 2

fsb4000 avatar Jan 09 '22 17:01 fsb4000

I have looked in the assembly.

if we comment out the static assert then the assembly has 2 more functions:

std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int> > >::<MarshalDestroy>

and

std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int> > >::<MarshalCopy>

fsb4000 avatar Jan 09 '22 20:01 fsb4000

I reduced a little bit more:

// main.cc, native code
#include <vector>

void apply(std::vector<int>::iterator) {}

extern void foo();

int main() {
    foo();
}
// mgd.cc, managed
#include <vector>

extern void apply(std::vector<int>::iterator b);

auto test() -> decltype(apply(std::vector<int>::iterator{}))
{}

void foo() {
    std::vector<int> v;
    apply(v.begin());
}

if "test" function is defined then we get the same assert error. If we comment out the "test" function then the program works fine.

fsb4000 avatar Jan 09 '22 21:01 fsb4000

one more time:

// main.cc, native code
struct dummy {
    int* a = nullptr;
    dummy() {
        a = new int[100];
    }
    dummy(const dummy&) {
        delete[] a;
        a = new int[100];
    }
    ~dummy() {
        delete[] a;
    }
};

void apply(dummy a) {}

extern void foo();

int main() {
    foo();
}
// mgd.cc, managed
struct dummy {
    int* a = nullptr;
    dummy() {
        a = new int[100];
    }
    dummy(const dummy&) {
        delete[] a;
        a = new int[100];
    }
    ~dummy() {
        delete[] a;
    }
};

extern void apply(dummy a);

auto test() -> decltype(apply(dummy{})) {}

void foo() {
    dummy v;
    apply(v);
}

if we comment out auto test() -> decltype(apply(dummy{})) {} then managed code uses dummy::<MarshalCopy> I might be wrong but I think it is a compiler issue. I think we should use dummy::<MarshalCopy> always. I will inform the compiler developers.

fsb4000 avatar Jan 09 '22 22:01 fsb4000

I created DevCom-1632617

fsb4000 avatar Jan 10 '22 06:01 fsb4000