- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here is a minimal reproduction:
[cpp]#include
int main() {
std::string wrong = "Goodbye, World!";
[wrong](){}();
return 0;
}[/cpp]
This trivial program, compiled in debug (/Od) or release mode with /Qstd=c++0x, aborts on the line containing the lambda.
Further experimentation reveals that capture-by-value with [=] or [var] works fine for built-in types (int, char*) but not for anything with a nondefault copy constructor. The following program gives some insight into what's wrong:
[cpp]#include
#include
using namespace std;
class Test {
public:
Test(int x)
: value(x)
{
cout << "Test " << value << " created at "
<< this << endl;
}
~Test() {
cout << "Test " << value << " destroyed at "
<< this << endl;
}
Test(const Test& r)
: value(r.value)
{
cout << "Test " << value << " copied from "
<< &r << " to new " << this << endl;
}
void operator=(const Test& r) {
value = r.value;
cout << "Test " << value << " assigned from "
<< &r << " to " << this << endl;
}
private:
int value;
};
int main() {
Test test(1);
[test](){}();
return 0;
}[/cpp]
The output from this program (in debug mode) on my computer is:
Test 1 created at 002FFCE4
Test 3144932 copied from 002FFCDC to new 002FFCEC
Test 3144932 destroyed at 002FFCEC
Test 1 destroyed at 002FFCE4
The copy constructor of Test is called with the wrong reference (pointing to some location on the stack which doesn't contain the original test object), and thus creates a completely invalid new object. It's easy to see why this results in Bad Things when copying std::string in the first example.
Microsoft Visual Studio 2010 Beta 1 runs these programs correctly, yielding for the second one:
Test 1 created at 003FFA18
Test 1 copied from 003FFA18 to new 003FF940
Test 1 destroyed at 003FF940
Test 1 destroyed at 003FFA18
Thanks for looking into this!
--void
(edited to report success on VS 2010, and to remove syntax that is accepted by Intel but not standard)
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
[cpp]#includeusing namespace std; class Test { public: Test(int x) : value(x) { } Test(const Test &r) : value(r.value) { cout << "source value is: " << r.value << endl; } private: int value; }; int main() { Test test(1); [test](){}(); return 0; } [/cpp]
Apparently, the copy constructor is called but the reference is invalid.
It is possibly a bug.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the help!
I updated my original post to report the results from the same program under VS 2010 (which works correctly). I have also noticed that the compiler generated function object created from a lambda itself has a user defined copy constructor (or the equivalent) that suffices to trigger the bug:
[cpp]#includeThis program produces this (incorrect) output on Intel:#include using namespace std; int main() { int number = 10; auto f = [=]() { cout << "number is " << number << endl; }; f(); auto g = [=]() { f(); }; g(); return 0; }[/cpp]
number is 10
number is 4193700
and this (correct) output on VS 2010 Beta 1:
number is 10
number is 10
I believe this is the same bug, and that my original bug report will be most useful for reproducing it, but a program like this one belongs in the test suite for the compiler as well. (At the risk of being snarky, DOES Intel test its compiler? It's a little hard for me to imagine a serious test suite for lambda functions that doesn't trigger this problem!)
I'm still hoping for a comment from Intel.
--void
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would try to submit it to Intel Premier Support, but unfortunately the website does not work! ("HTTP 500 - Internal Server Error")
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for posting the issue report here. I've filed a bug report (DPD200140177) to the compiler engineer. Once it's fixed, I'll post the news to this thread.
Jennifer
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks. For what it's worth, in my last post I meant 11.1.046.
--void
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Have the same problem on 11.1.071 Windows
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
And have the same problem in 11.1.072 Windows x64 - compiles fine, wrong address for object passed
From running through the Dissassembly window the following sequence of events occures
1) Lambda capture context block space reserved on stack
2) for simple variables [=] copies fine
3) for objects passed by [=] and with copy constructor T(const volatile T& refT) is called for the copy (it would be nice if this where documented. However it is called in error.
a) the address within the Lambda capture context block is correct (IOW target of the ctor is ok)
b) the address of the refT (the reference) is copied to a stack temporary
c) the address of the stack temporary is pass to the copy constructor (ctor then trashes memory)
d) the address of the stack temporary is inserted into the Lambda capture context block and passed (later) into the Lambda function.
Effectively the copy constructor receives T&& refrefT
The above may help your developers in tracking down the problem
Also, I surmize the first reference is copied to the stack temp as a byproduct of the volatile type. The volatile type should cause the compiler to generate code the _read_ a fresh copy of the reference from memory when passing to copy constructor and NOT write copy to memory and then re-read that. Although in this case it is issuing something like
lea rax,[loc]
when it should be issuing
mov rax, [loc]
The memory temp should not be required/used in this case.
Seperate, but related issue
The Lambda capture context block needs a copy constructor.
Reason being, the Lambda capture context block is constructed on the current stack.
When you need to run an asynchronous task that may not begin to run until _after_ the scope in which the Lambda capture context block was constructed. Then you cannot use the original Lambda capture context block, but you can use a copy of this block, provided you make the copy (which is QED using a template). Under the current circumstance: Address of Lambda capture context blockconstructed on the current stack passed to asynchronous task, when task runs after dtor of Lambda capture context blockconstructed on _then_ current stack, the task sees a corrupted Lambda capture context block.
Jim Dempsey
www.quickthreadprogramming.com
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jennifer,
RE:
The Lambda capture context block needs a copy constructor.
Reason being, the Lambda capture context block is constructed on the current stack.
In running additional test the copy constructor/operator is working properly same with the dtor on the copy of the Lambda capture block.
Therefor this is no problem.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This issue has been fixed in the latest Intel C++ Composer XE. The compiler is available from our registration and download center.
Thanks,
Om
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page