Consider the following simple code:
template<typename T>
struct Base {
static constexpr int v = 0;
};
struct Derived : Base<int> {};
int main() {
Derived d;
}
I compile it with GCC (8.3.0, 9.1.0, g++ -g -O0 test.cpp), then run GDB to examine the value of d:
(gdb) p d
$1 = {<Base<int>> = {static v = <optimized out>}, <No data fields>}
d.v is gone... I tried to use -ggdb, -ggdb3, -fvar-tracking with no success.
If I compile with clang (clang++ -g -O0 test.cpp), I see the expected result:
(gdb) p d
$1 = {<Base<int>> = {static v = 0}, <No data fields>}
This output is also seen with GCC if Base is not a template class:
(gdb) p d
$1 = {<Base> = {static v = 0}, <No data fields>}
Where did d.v go? Why was it optimized out? Is it possible to prevent this optimization without modifying the source code?
Even though it doesn't have to respect it, by using constexpr and providing an initialized value, you're strongly hinting to the compiler that it should constant-fold Base::v.
Gcc has a -fkeep-static-consts flag that might do what you want.
Related
I can get more debug info if built my program on Windows compared to Linux.
Here is my code:
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
Base() = default;
virtual ~Base() = default;
};
class Derived : public Base
{
public:
Derived() = default;
~Derived() = default;
private:
int i = 1;
};
int main()
{
vector<Base*> a;
a.push_back(new Derived());
return 0;
}
Build On Linux:
Build On Windows:
It's obvious I can get more information with Windows build version. Such as vector info, vector element real type, derived object info... But Linux version, I only get the pointer address. By the way, they are all debugging by visual studio. Is there some way to add more debug info to the program built by GNU compiler? Such as compiler flags?
I don't use visual studio, so not sure how you will make use of this answer from within that environment, however, I think you can get what you want using the GDB setting: set print object on.
To show this in action, here's my GDB (12.1) session, using the same test program that you posted:
$ gdb -q vec.x
Reading symbols from vec.x...
(gdb) b 26
Breakpoint 1 at 0x401245: file vec.cc, line 26.
(gdb) r
Starting program: /tmp/vec.x
Breakpoint 1, main () at vec.cc:26
26 return 0;
(gdb) p a
$1 = std::vector of length 1, capacity 1 = {0x418eb0}
(gdb) p a[0]
$2 = (Base *) 0x418eb0
(gdb) p *a[0]
$3 = {
_vptr.Base = 0x403040 <vtable for Derived+16>
}
(gdb) set print object on
(gdb) p a[0]
$4 = (Derived *) 0x418eb0
(gdb) p *a[0]
$5 = (Derived) {
<Base> = {
_vptr.Base = 0x403040 <vtable for Derived+16>
},
members of Derived:
i = 1
}
(gdb) q
I fixed this problem by add a init command to the ~/.gdbinit.
Add the following command to the first line of file ~/.gdbinit.
set print object on
I like to cast a void pointer back to unique_ptr<T> with arbitrary type T so that I can dereference it to the contents of it. But with the following simple example:
#include <memory>
class Foo {
public: Foo(){};
};
int main() {
std::unique_ptr<Foo> p1 (new Foo);
void *p2 = (void*)&p1;
return 0;
}
I get the following error and not be able to cast:
$ gdb ./unique-ptr
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
(gdb) b 10
Breakpoint 1 at 0x400682: file unique-ptr.cc, line 10.
(gdb) run
Starting program: /home/vagrant/c-test/unique-ptr/unique-ptr
Breakpoint 1, main () at unique-ptr.cc:10
10 return 0;
(gdb) p p1
$1 = std::unique_ptr<Foo> containing 0x603010
(gdb) p p2
$2 = (void *) 0x7fffffffea40
(gdb) p *(std::unique_ptr<Foo>*)p2
A syntax error in expression, near `)p2'.
(gdb)
Actual use case is that I like to print out contents of unique_ptr contained in container class, but this is the issue currently preventing me to go further.
The actual type name created with the template is not std::unique_ptr<Foo>. Obtain the real type name with:
(gdb) ptype p1
type = class std::unique_ptr<Foo, std::default_delete<Foo> > [with _Tp = Foo, _Dp = std::default_delete<Foo>] {
private:
__tuple_type _M_t;
...
From this, I figured out that gdb recognizes std::unique_ptr<Foo, std::default_delete<Foo> >, and I was able to do:
(gdb) p *(std::unique_ptr<Foo, std::default_delete<Foo> > *)p2
$3 = std::unique_ptr<Foo> containing 0x603010
which matches with
(gdb) p p1
$1 = std::unique_ptr<Foo> containing 0x603010
This question already has answers here:
Why gdb casting is not working?
(4 answers)
Closed 6 years ago.
From this link
gdb interpret memory address as an object
we know that, if an object of class type A is at a specific address such as 0x6cf010, then we can use:
(gdb) p *(A *) 0x6cf010
to print the member elements of this object.
However, this seems doesn't work when c++ namespace is involved. That is, if the object of class type A::B, then all the following trying doesn't work:
(gdb) p *(A::B *) 0x6cf010
(gdb) p *((A::B *) 0x6cf010)
So, who knows how to print the object elements under this conditions?
We can use the following deliberate core code to try to print the members of p from the address (we can use "info locals" to show the address).
#include <stdio.h>
namespace A
{
class B
{
public:
B(int a) : m_a(a) {}
void print()
{
printf("m_a is %d\n", m_a);
}
private:
int m_a;
};
}
int main()
{
A::B *p = new A::B(100);
p->print();
int *q = 0;
// Generating a core here
*q = 0;
return 0;
}
I know that this is labeled as answered, but I was able to reproduce this problem using gdb on OS X (GNU gdb 6.3.50-20050815 (Apple version gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)) and the works-for-me solution didn't answer it for me.
Turns out there was another question on SO that did have an answer which worked, so I think it's worth pulling into this quesiton:
Why gdb casting is not working?
The short answer is that you may have to single-quote your namespaced variables:
(gdb) p ('MyScope::MyClass'*) ptr;
Works for me:
g++ -g test.cpp -o test
gdb test
(gdb) break main
(gdb) r
Breakpoint 1, main () at test.cpp:22
22 A::B *p = new A::B(100);
(gdb) n
24 p->print();
(gdb) n
m_a is 100
26 int *q = 0;
(gdb) p p
$1 = (A::B *) 0x602010
(gdb) p (A::B *) 0x602010
$2 = (A::B *) 0x602010
(gdb) p *((A::B *) 0x602010)
$3 = {m_a = 100}
It works for me. What are you using (gcc version, OS, compilation flags?)
I have a class A as follows:
class A
{
public:
A()
{
printf("A constructed\n");
}
~A();
//no other constructors/assignment operators
}
I have the following elsewhere
A * _a;
I initalize it with:
int count = ...
...
_a = new A[count];
and I access it with
int key = ....
...
A *a_inst = &(_a[key]);
....
It runs normally, and the printf in the constructor is executed, and all the fields in A are fine.
I ran Valgrind with the following args:
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./A_app
and Valgrind keeps yelling about
Conditional jump or move depends on uninitialised value(s)
and then the stack trace to the accessors statements.
Can anyone explain why this is happening? Specifically if what Valgrind says is true, why is the constructor executed?
This can mean that key or count contains an uninitialized value. Even if you do initialize it in the declaration, e.g. int key = foo + bar;, it could be that either foo or bar is uninitialized, and valgrind carries this over to key.
Edit: Try setting A *a = 0;
Running your code in an a simplified scenario does not produce any warnings from Valgrind. Consider the following code:
#include <iostream>
class A
{
public:
A()
{
std::cout << "A" << std::endl;
}
};
int main()
{
A *a;
int count = 10;
a = new A[count];
int key = 1;
A *inst = &(a[key]);
return 0;
}
Compiled with:
$ g++ -g main.cc -o main
and run with:
$ valgrind --leak-check=full --show-reachable=yes --track-origins=yes ./main
So, I think more information is needed. You are likely doing something between defining _a and actually allocating memory on the heap. Might I simply suggest that you merge the definition and allocation into one line?
int count = 10;
A *a = new A[count];
I defined a class named nth_best_parse this way:
class nth_best_parse {
public:
int traversal;
int nth_best_active;
int nth_best_passive;
double viterbi_prob;
nth_best_parse();
nth_best_parse(int t, int nbl, int nbr, double v) {traversal = t; nth_best_active = nbl; nth_best_passive = nbr; viterbi_prob = v;}
};
Then I declared vectors of this nth_best_parse as members of two different classes:
class Edge { // an edge associates an Earley style dotted-item with a span
public:
<some irrelevant stuff>
Span span; // Span of the edge
bool isActive;
vector<Traversal *> leading_traversals; // The list of traversals which lead to parsing of this edge
vector<nth_best_parse> n_best_parses;
union {
DottedRule rule_state; // Accessed if isActive is true
int symbol; // Accessed if isActive is false
// A symbol corresponding to the category of a passive edge
// Put inside this union to save space
};
inline int span_length() {return span.end - span.start;}
};
<some other stuff>
class BPCFGParser {
public:
// Some data structures used in intermediary computations for calculating the n-best parses
// vector<vector<int> > nth_best_pairs;
vector<vector<nth_best_parse> > n_best_pairs_for_traversals;
<some other stuff>
void compute_n_best_parses(Edge *e, int n);
<some other stuff>
}
Then I run this program with gdb (by the way, I'm using Linux Ubuntu 9.04, g++ 4.3.3,GNU gdb 6.8-debian) and set a breakpoint at the end of the definition of compute_n_best_parses() with some conditions (to locate the exact call of this function I wanted, I was tracing back from a segmentation fault). When gdb hit the breakpoint, I issued a set of commands and the gdb output was like this:
(gdb) print e->n_best_parses.size()
$27 = 1
(gdb) print e->n_best_parses[0]
$28 = (nth_best_parse &) #0x1e96240: {traversal = 0, nth_best_active = 0, nth_best_passive = 0, viterbi_prob = 0.16666666666666666}
(gdb) print e->n_best_parses[0].traversal
$29 = 0
(gdb) print &(e->n_best_parses[0].traversal)
$30 = (int *) 0x1e96240
(gdb) awatch *$30
Hardware access (read/write) watchpoint 6: *$30
(gdb) print e->n_best_parses
$31 = {<std::_Vector_base<nth_best_parse, std::allocator<nth_best_parse> >> = {
_M_impl = {<std::allocator<nth_best_parse>> = {<__gnu_cxx::new_allocator<nth_best_parse>> = {<No data fields>}, <No data fields>},
_M_start = 0x1e96240, _M_finish = 0x1e96258, _M_end_of_storage = 0x1e96288}}, <No data fields>}
(gdb) continue
Continuing.
Hardware access (read/write) watchpoint 6: *$30
Old value = 0
New value = 1
0x0000000000408a4c in __gnu_cxx::new_allocator<nth_best_parse>::construct<nth_best_parse> (this=0x1e96208, __p=0x1e96240, __args#0=#0x7fff8ad82260)
at /usr/include/c++/4.3/ext/new_allocator.h:114
114 { ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); }
(gdb) backtrace
#0 0x0000000000408a4c in __gnu_cxx::new_allocator<nth_best_parse>::construct<nth_best_parse> (this=0x1e96208, __p=0x1e96240, __args#0=#0x7fff8ad82260)
at /usr/include/c++/4.3/ext/new_allocator.h:114
#1 0x000000000042169c in std::vector<nth_best_parse, std::allocator<nth_best_parse> >::push_back<nth_best_parse> (this=0x1e96208, __args#0=#0x7fff8ad82260)
at /usr/include/c++/4.3/bits/stl_vector.h:703
#2 0x0000000000402bef in BPCFGParser::compute_n_best_parses (this=0x7fff8ad82770, e=0x7f5492858b78, n=3) at BPCFGParser.cpp:639
#3 0x00000000004027fd in BPCFGParser::compute_n_best_parses (this=0x7fff8ad82770, e=0x7f5492859d58, n=3) at BPCFGParser.cpp:606
#4 0x00000000004027fd in BPCFGParser::compute_n_best_parses (this=0x7fff8ad82770, e=0x7f549285a1d0, n=3) at BPCFGParser.cpp:606
#5 0x00000000004064d8 in main () at experiments.cpp:75
Line 639 of BPCFGParser.cpp was like this:
PUSH_BEST_PAIR_FOR_TRAVERSAL(i,row,column,grammar->probs[temp_rule.symbol][temp_rule.expansion]);
This was a macro defined at the beginning of the file as:
#define PUSH_BEST_PAIR_FOR_TRAVERSAL(x,y,z,t) n_best_pairs_for_traversals[x].push_back(nth_best_parse(x, y, z, e->leading_traversals[x]->active_edge->n_best_parses[y].viterbi_prob * e->leading_traversals[x]->passive_edge->n_best_parses[z].viterbi_prob * t))
By the way, class Traversal is defined as:
class Traversal { // Class for a traversal
public:
Edge *active_edge;
Edge *passive_edge;
Traversal();
Traversal(Edge *a, Edge *p) {active_edge = a; passive_edge = p;}
};
So actually I'm pushing something to the vector n_best_pairs_for_traversals, which is a member of an instance of the class BPCFGParser and the push_back() code somehow overwrites on the vector n_best_parses, which is a member of an instance of the class Edge. How can this ever be possible?
You obviously have memory corruption problems somewhere.
BUT there is not enough here information to help you.
But you are writing C++ code and your class contain pointers.
This is not a good sign (there should hardly ever be a RAW pointer in a C++ class).
This is also often the cause of memory corruption for inexperienced C++ developers!
Have you obeyed the rule of 4?
Make sure every class that contains RAW owned pointers:
constructor
copy constructor
assignment operator
destructor.
Are you sure you're passing a valid first argument to your macro? Maybe you're accessing out of bounds when doing n_best_pairs_for_traversals[x] because x is larger than the vector size.
I'd guess that you are using a vector to store objects (perhaps Traversal?), not realizing that pushing new elements onto that vector can invalidate pointers to elements already in the vector. Use a deque instead if this is the case.