Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > std::move and vc10: bug or misunderstanding?

Reply
Thread Tools

std::move and vc10: bug or misunderstanding?

 
 
Daniel
Guest
Posts: n/a
 
      05-24-2013
Consider the following boost test case:

#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <utility>
#include <string>

class A
{
public:
void value(std::string s)
{
s_ = s;
}
std::string s_;
};

class B
{
public:
void f()
{
for (size_t i = 0; i < 10; ++i)
{
buffer_ = "Hello world";
a.value(std::move(buffer_));
}
}
A a;
std::string buffer_;
};


BOOST_AUTO_TEST_CASE( test1 )
{
B b;
b.f();
}

When run, boost reports 9 occurrences of memory leaks. These leaks vanish when the signature of the value method is changed to value(std:;string&& s); But the original program shouldn't leak, should it? Or am I misunderstanding something?

Thanks,
Daniel
 
Reply With Quote
 
 
 
 
SG
Guest
Posts: n/a
 
      05-24-2013
On May 24, 3:29*am, Daniel wrote:
>
> #define BOOST_TEST_MAIN
> #include <boost/test/unit_test.hpp>
> #include <utility>
> #include <string>
>
> class A
> {
> public:
> * * void value(std::string s)
> * * {
> * * * * s_ = s;
> * * }
> * * std::string s_;
> };


Since you are in C++11 mode, you could replace

s_ = s;

with

s_ = move(s);

> class B
> {
> public:
> * * void f()
> * * {
> * * * * for (size_t i = 0; i < 10; ++i)
> * * * * {
> * * * * * * buffer_ = "Hello world";
> * * * * * * a.value(std::move(buffer_));
> * * * * }
> * * }
> * * A a;
> * * std::string buffer_;
> };
>
> BOOST_AUTO_TEST_CASE( test1 )
> {
> * * B b;
> * * b.f();
> }
>
> When run, boost reports 9 occurrences of memory leaks.


That's weird. I don't know enough about Boost.Test to explain this but
your program definitely does not contain any memory leaks -- assuming
the std::string implementation is free of bugs. Maybe your std::string
implementation has its own heap management that does not immediately
deallocate memory of a shirt-lived temporary.

> These leaks vanish when the signature of the value method is changed
> to value(std:;string&& s);


By doing that you just avoid the creation of a lot of temporary string
objects.

> But the original program shouldn't leak,
> should it? Or am I misunderstanding something?


No, it should not.

I just tried your test using g++ (tdm64-1) 4.6.1 and Boost 1.53 with
the following result:

Running 1 test case...

*** No errors detected

Cheers!
SG
 
Reply With Quote
 
 
 
 
Daniel
Guest
Posts: n/a
 
      05-24-2013
On Friday, May 24, 2013 2:05:36 AM UTC-4, Paavo Helde wrote:
> Daniel wrote in
>
> > Consider the following boost test case:

>
> As there is not a single 'new' in your code, there shouldn't be any leak.
>
> So it seems either the std::string implementation or the Boost memory
>
> leak detector seems to be buggy, or something else. On my machine (MSVC
>
> 2010 64-bit, old Boost (1.44)) your test does not report any leaks.
>
>

Thanks Paavo, I really appreciate your feedback, and that you tried this yourself. As your env is similar to mine (except boost 1.4, I ran the testsagain, and observed that the reported leaks only occurred in Debug, not Release. It's nice to know that this isn't a C++ issue.

Thanks,
Daniel

 
Reply With Quote
 
Daniel
Guest
Posts: n/a
 
      05-24-2013
On Friday, May 24, 2013 5:34:02 AM UTC-4, SG wrote:
> On May 24, 3:29*am, Daniel wrote:
>
>
> I just tried your test using g++ (tdm64-1) 4.6.1 and Boost 1.53 with
>
> the following result:
>
>
>
> Running 1 test case...
>
>
>
> *** No errors detected
>

Thanks SG, really appreciate that you tried this, after Paavo's feedback and your's, I reran the test, and observed that the leaks, e.g.

Detected memory leaks!
Dumping objects ->
{713} normal block at 0x007BCB98, 16 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

are only reported in Debug, not Release. It's nice to know that this is nota C++ issue.

Thanks,
Daniel
 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      05-24-2013
On 5/24/2013 8:39 AM, Daniel wrote:
> On Friday, May 24, 2013 5:34:02 AM UTC-4, SG wrote:
>> On May 24, 3:29 am, Daniel wrote:
>>
>>
>> I just tried your test using g++ (tdm64-1) 4.6.1 and Boost 1.53 with
>>
>> the following result:
>>
>>
>>
>> Running 1 test case...
>>
>>
>>
>> *** No errors detected
>>

> Thanks SG, really appreciate that you tried this, after Paavo's feedback and your's, I reran the test, and observed that the leaks, e.g.
>
> Detected memory leaks!
> Dumping objects ->
> {713} normal block at 0x007BCB98, 16 bytes long.
> Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
>
> are only reported in Debug, not Release. It's nice to know that this is not a C++ issue.


In order for them to be reported in Release you need to use special
tools. In Debug those tools are incorporated into your executable by
the compiler/linker. IOW, if you don't see any leaks in Release, it's
not because there aren't any leaks, it's because you don't look with
proper tools.

If you want to learn more about available tools from Microsoft, read up
on _CrtMemCheckpoint (and related functions), start here:
http://msdn.microsoft.com/en-us/libr...v=vs.100).aspx
, or just search the web for "debugging memory leak windows". Plenty of
info available.

V
--
I do not respond to top-posted replies, please don't ask
 
Reply With Quote
 
Geoff
Guest
Posts: n/a
 
      05-24-2013
On Fri, 24 May 2013 05:31:01 -0700 (PDT), Daniel
<(E-Mail Removed)> wrote:

>On Friday, May 24, 2013 2:05:36 AM UTC-4, Paavo Helde wrote:
>> Daniel wrote in
>>
>> > Consider the following boost test case:

>>
>> As there is not a single 'new' in your code, there shouldn't be any leak.
>>
>> So it seems either the std::string implementation or the Boost memory
>>
>> leak detector seems to be buggy, or something else. On my machine (MSVC
>>
>> 2010 64-bit, old Boost (1.44)) your test does not report any leaks.
>>
>>

>Thanks Paavo, I really appreciate your feedback, and that you tried this yourself. As your env is similar to mine (except boost 1.4, I ran the tests again, and observed that the reported leaks only occurred in Debug, not Release. It's nice to know that this isn't a C++ issue.
>


You don't see the leaks in release mode because the release mode code
doesn't check and report them.
 
Reply With Quote
 
Daniel
Guest
Posts: n/a
 
      05-24-2013
On Friday, May 24, 2013 9:10:57 AM UTC-4, Victor Bazarov wrote:
>
>
> In order for them to be reported in Release you need to use special
>
> tools. In Debug those tools are incorporated into your executable by
>
> the compiler/linker. IOW, if you don't see any leaks in Release, it's
>
> not because there aren't any leaks, it's because you don't look with
>
> proper tools.
>

Thanks for pointing that out!

Best regards,
Daniel
 
Reply With Quote
 
Gert-Jan de Vos
Guest
Posts: n/a
 
      05-24-2013
On Friday, May 24, 2013 2:31:01 PM UTC+2, Daniel wrote:
> On Friday, May 24, 2013 2:05:36 AM UTC-4, Paavo Helde wrote:
>
> > Daniel wrote in
> >
> > > Consider the following boost test case:

> > As there is not a single 'new' in your code, there shouldn't be any leak.
> > So it seems either the std::string implementation or the Boost memory
> > leak detector seems to be buggy, or something else. On my machine (MSVC
> > 2010 64-bit, old Boost (1.44)) your test does not report any leaks.
> >

> Thanks Paavo, I really appreciate your feedback, and that you tried this
> yourself. As your env is similar to mine (except boost 1.4, I ran the
> tests again, and observed that the reported leaks only occurred in Debug,
> not Release. It's nice to know that this isn't a C++ issue.


I ran your test with MSVC10 SP1, 32 bit, boost-1.51.0, Debug: no leaks. If
I add this leak: "new int;" I see just this single 4 byte leak reported.

Did you install Service Pack 1?

Gert-Jan
 
Reply With Quote
 
Daniel
Guest
Posts: n/a
 
      05-25-2013
On Friday, May 24, 2013 4:12:24 PM UTC-4, Gert-Jan de Vos wrote:
>
>
> Did you install Service Pack 1?
>


Yes, Microsoft Visual Studio 2010 Version 10.0.40219.1 SP1Rel, however, given what others are reporting, I'm starting to feel like a minority of one! I better head over to an msdn group, a big thanks to everyone here for your help.

Daniel
 
Reply With Quote
 
pasa
Guest
Posts: n/a
 
      05-25-2013
On May 24, 3:29 am, Daniel <(E-Mail Removed)> wrote:
> class A
> {
> public:
> void value(std::string s)
> {
> s_ = s;
> }
> std::string s_;
> };
>
> class B
> {
> public:
> void f()
> {
> for (size_t i = 0; i < 10; ++i)
> {
> buffer_ = "Hello world";
> a.value(std::move(buffer_));
> }
> }
> A a;
> std::string buffer_;
>
> };
>
> BOOST_AUTO_TEST_CASE( test1 )
> {
> B b;
> b.f();
> }
>
> When run, boost reports 9 occurrences of memory leaks. These leaks vanish when the signature of the value method is changed to value(std:;string&& s); But the original program shouldn't leak, should it? Or am I misunderstanding something?


This looks a bug in MS' implementation of std::string.

The leaked thing is allocated in this function:
file xstring line 1981
void _Copy(size_type _Newsize, size_type _Oldlen)
{ // copy _Oldlen elements to newly allocated buffer
size_type _Newres = _Newsize | this->_ALLOC_MASK;
if (max_size() < _Newres)
_Newres = _Newsize; // undo roundup if too big
else if (this->_Myres / 2 <= _Newres / 3)
;
else if (this->_Myres <= max_size() - this->_Myres / 2)
_Newres = this->_Myres
+ this->_Myres / 2; // grow exponentially if possible
else
_Newres = max_size(); // settle for max_size()

_Elem *_Ptr;
_TRY_BEGIN
_Ptr = this->_Alval.allocate(_Newres + 1);
_CATCH_ALL
_Newres = _Newsize; // allocation failed, undo roundup and retry
_TRY_BEGIN
_Ptr = this->_Alval.allocate(_Newres + 1);
_CATCH_ALL
_Tidy(true); // failed again, discard storage and reraise
_RERAISE;
_CATCH_END
_CATCH_END

if (0 < _Oldlen)
_Traits::copy(_Ptr, _Myptr(), _Oldlen); // copy existing elements
_Tidy(true);
this->_Bx._Ptr = _Ptr;
this->_Myres = _Newres;
_Eos(_Oldlen);
}

By the allocate() call in the middle. The pointer is stored in the
union that holds the sting state -- the 16 byte directly or the
pointer to the allocated external storage. It is immediately trampled
over by the last line, calling _Eos, that looks at the length of 11
and treats the union as directly holding the material, applying the 0
terminator at front. The bug is that we should not be here in the
first place.

The caller is
xstring:1957
bool _Grow(size_type _Newsize,
bool _Trim = false)
{ // ensure buffer is big enough, trim to size if _Trim is true
if (max_size() < _Newsize)
_Xlen(); // result too long
if (this->_Myres < _Newsize)
_Copy(_Newsize, this->_Mysize); // reallocate to grow
else if (_Trim && _Newsize < this->_BUF_SIZE)
_Tidy(true, // copy and deallocate if trimming to small string
_Newsize < this->_Mysize ? _Newsize : this->_Mysize);
else if (_Newsize == 0)
_Eos(0); // new size is zero, just null terminate
return (0 < _Newsize); // return true only if more work to do
}
the second if.
I'm lazy to look further, my best guess is that a previous move-from
breaks the internal state, setting the "capacity" to zero instead of
16, that triggers this Grow.

The bug happens only if the content fits the small-string buffer (15+1
chars), with bigger one it is okay.

Good addition to my list of why we should avoid this crapbag called
std::string.

I guess MS will not release any corrections to VS2010 (I recall a deal
of serious bugs closed with nofix), so if you want to actually use
something like this, find the source problem in the move assignment,
then install the modified xstring file to all your machines. Or use
CString or some other sensible string implementation.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
*bug* *bug* *bug* David Raleigh Arnold Firefox 12 04-02-2007 03:13 AM
ASP.NET Login control bug or SQL 2005 bug? RedEye ASP .Net 2 12-13-2005 10:57 AM
Re: BUG? OR NOT A BUG? John ASP .Net 2 09-21-2005 10:31 AM
rdoc bug (and rdoc bug tracker site is down) Brian Schröder Ruby 5 09-18-2004 02:08 PM
how to report bug to g++ ? got a bug and fixed up source code DarkSpy C++ 4 06-27-2003 09:05 AM



Advertisments