Discussion:
std::string clobbers memory when compiling without optimizations
Henrik Mannerström
2014-10-03 08:18:57 UTC
Permalink
Hello,

I found a program that produces incorrect behavior when compiling with
-Og or without optimization. By running gdb I can pinpoint the problem
to the std::string constructor, but I have to do more research to be
able to step through that with gdb. My minimal working example is not so
minimal, but I have not been able to reproduce the problem with a
smaller program. The Eigen library used is from eigen.tuxfamily.org . On
the line indicated by "Correct output" the program prints what I expect,
two lines later, the contents has changed. With gdb I can see that the
memory content is changed by the std::string namestring(name) line in
the t2s function. Watching the memory location that is changed gives
std::basic_string<char, std::char_traits<char>, std::allocator<char>
::basic_string(char const*, std::allocator<char> const&) as the
offending location. Compiling with g++-4.9 -std=c++11 gives the error,
but adding -O1 produces correct results.

Do you have any suggestions on what to do next?

BR,
Henrik Mannerström




#include <cxxabi.h>
#include <string>
#include <typeinfo>
#include <cstdlib>

template <typename T>
std::string t2s(T tt) {
char *name;
int status;
name = abi::__cxa_demangle(typeid(tt).name(), 0, 0, &status);
std::string namestring(name); // Variable Sigma from main is changed
at this line.
std::free(name);
return namestring;
}

#include <Eigen/Core>
#include <iostream>

int main() {
typedef Eigen::Matrix<double, 1, 3> cVector;

const cVector mean = (cVector() << 1, 2, 3).finished();
const auto Sigma = (cVector() << 1, 1, 1).finished().asDiagonal();

std::cout << "Correct diagonal: " << Sigma.diagonal() << std::endl; //
Correct output: 1 1 1

std::cout << t2s(mean) << std::endl;

std::cout << "Incorrect diagonal: " << Sigma.diagonal() << std::endl;
// Incorrect output: [random double] 1 1
}
Jonathan Wakely
2014-10-03 09:58:36 UTC
Permalink
Post by Henrik Mannerström
Do you have any suggestions on what to do next?
Have you tried valgrind?

Or compiling with GCC's -fstack-protector option?

I can't reproduce the problem, and I think it's pretty unlikely
std::string has that kind of bug without someone noticing years ago.
Henrik Mannerström
2014-10-03 10:08:57 UTC
Permalink
Hi,
Have you tried valgrind? Or compiling with GCC's -fstack-protector
option? I can't reproduce the problem, and I think it's pretty
unlikely std::string has that kind of bug without someone noticing
years ago.
I'm not assuming that std::string has a bug (even though the title might
suggest that), I'm just saying that the gdb watchpoint is triggered
inside that function. I tried valgrind memcheck, but I'm no expert, so
suggestions are welcome. Below is the output with stack-protector, what
do you make out of it? Could it be my installation?

- Henrik


$ g++-4.9 -std=gnu++1y mvu.cc -o mvu
$ ./mvu
Correct diagonal: 1 1 1
Eigen::Matrix<double, 1, 3, 1, 1, 3>
Incorrect diagonal: 1.81749e-316 1 1
$ g++-4.9 -std=gnu++1y -fstack-protector-all mvu.cc -o mvu
$ ./mvu
Correct diagonal: 1 1 1
Eigen::Matrix<double, 1, 3, 1, 1, 3>
Incorrect diagonal: 1 2 3
$ g++-4.9 -std=gnu++1y -O1 -fstack-protector-all mvu.cc -o mvu
$ ./mvu
Correct diagonal: 1 1 1
Eigen::Matrix<double, 1, 3, 1, 1, 3>
Incorrect diagonal: 1 1 1

g++-4.9 (Ubuntu 4.9.1-3ubuntu2~14.04.1) 4.9.1
Copyright (C) 2014 Free Software Foundation, Inc.
Jonathan Wakely
2014-10-03 10:20:40 UTC
Permalink
Post by Henrik Mannerström
Hi,
Have you tried valgrind? Or compiling with GCC's -fstack-protector
option? I can't reproduce the problem, and I think it's pretty
unlikely std::string has that kind of bug without someone noticing
years ago.
I'm not assuming that std::string has a bug (even though the title might
suggest that), I'm just saying that the gdb watchpoint is triggered
inside that function. I tried valgrind memcheck, but I'm no expert, so
suggestions are welcome. Below is the output with stack-protector, what
do you make out of it? Could it be my installation?
- Henrik
$ g++-4.9 -std=gnu++1y mvu.cc -o mvu
$ ./mvu
Correct diagonal: 1 1 1
Eigen::Matrix<double, 1, 3, 1, 1, 3>
Incorrect diagonal: 1.81749e-316 1 1
$ g++-4.9 -std=gnu++1y -fstack-protector-all mvu.cc -o mvu
$ ./mvu
Correct diagonal: 1 1 1
Eigen::Matrix<double, 1, 3, 1, 1, 3>
Incorrect diagonal: 1 2 3
I get the same "1 2 3" result using -fstack-protector-all and valgrind.

My guess is that Sigma holds a dangling reference to some temporary
object that has gone out of scope, and the function call t2s
overwrites that stack memory, then when you return to main you go
through the dangling reference.

Are you sure you're using the Eigen types correctly?
Henrik Mannerström
2014-10-03 10:30:57 UTC
Permalink
Post by Jonathan Wakely
My guess is that Sigma holds a dangling reference to some temporary
object that has gone out of scope, and the function call t2s
overwrites that stack memory, then when you return to main you go
through the dangling reference.
Are you sure you're using the Eigen types correctly?
You are right, the auto type does not force the evaluation of Sigma,
which leaves the dangling reference. Yet again I get burned by trying to
combine Eigen and C++11. How would you classify this, could you call it
a bug in Eigen, or just incompatibility with C++11?

Thank you for you time.

- Henrik
Jonathan Wakely
2014-10-03 12:36:03 UTC
Permalink
Post by Henrik Mannerström
Post by Jonathan Wakely
My guess is that Sigma holds a dangling reference to some temporary
object that has gone out of scope, and the function call t2s
overwrites that stack memory, then when you return to main you go
through the dangling reference.
Are you sure you're using the Eigen types correctly?
You are right, the auto type does not force the evaluation of Sigma,
which leaves the dangling reference. Yet again I get burned by trying to
combine Eigen and C++11. How would you classify this, could you call it
a bug in Eigen, or just incompatibility with C++11?
As Marc says, expression templates are often incompatible with 'auto',
that doesn't mean Eigen is incompatible with C++11 in general.

Marc Glisse
2014-10-03 10:31:47 UTC
Permalink
Post by Jonathan Wakely
Post by Henrik Mannerström
Hi,
Have you tried valgrind? Or compiling with GCC's -fstack-protector
option? I can't reproduce the problem, and I think it's pretty
unlikely std::string has that kind of bug without someone noticing
years ago.
I'm not assuming that std::string has a bug (even though the title might
suggest that), I'm just saying that the gdb watchpoint is triggered
inside that function. I tried valgrind memcheck, but I'm no expert, so
suggestions are welcome. Below is the output with stack-protector, what
do you make out of it? Could it be my installation?
- Henrik
$ g++-4.9 -std=gnu++1y mvu.cc -o mvu
$ ./mvu
Correct diagonal: 1 1 1
Eigen::Matrix<double, 1, 3, 1, 1, 3>
Incorrect diagonal: 1.81749e-316 1 1
$ g++-4.9 -std=gnu++1y -fstack-protector-all mvu.cc -o mvu
$ ./mvu
Correct diagonal: 1 1 1
Eigen::Matrix<double, 1, 3, 1, 1, 3>
Incorrect diagonal: 1 2 3
I get the same "1 2 3" result using -fstack-protector-all and valgrind.
My guess is that Sigma holds a dangling reference to some temporary
object that has gone out of scope, and the function call t2s
overwrites that stack memory, then when you return to main you go
through the dangling reference.
Are you sure you're using the Eigen types correctly?
He is using "auto" with an expression template library, so I'd say that it
is unlikely he is using it correctly, indeed...
--
Marc Glisse
Loading...