Mysterious write violation on my variable - c++

I have an library that don't give correct output. I guess it is possibly an write violation, and focused it on this section of code:
void Page::build_default_frame(PosType genome_display_length)
{
Frame* frame = new Frame(*this,
margin_left,
margin_top,
width - margin_left - margin_right,
genome_display_length);
default_frame = frame;
frames.insert(default_frame);
}
The default_frame is a boost intrusive_ptr<Frame>.
Before execute the sentence default_frame = frame, the content of object frame was all right, but after that, its contents were modified to weird value. So I set two watches on two member variables of frame object:
(gdb) watch -l frame->genome_scale.genome_display_length
Hardware watchpoint 4: -location frame->genome_scale.genome_display_length
(gdb) watch -l frame->genome_scale.frame_width
Hardware watchpoint 5: -location frame->genome_scale.frame_width
and then continue. It suddenly reports write operation on these address:
(gdb) c
Continuing.
Hardware watchpoint 4: -location frame->genome_scale.genome_display_length
Old value = 1000
New value = 16
_dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:39
39 ../sysdeps/x86_64/dl-trampoline.S: No such file or directory.
(gdb) bt
#0 _dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:39
#1 0x00007ffff7b93dd0 in geno_eye::Page::build_default_frame (this=0x6071b0, genome_display_length=1000)
at /home/yangxi/projects/GenoEye/src/geno_eye/Page.cpp:127
#2 0x00007ffff7b93cc1 in geno_eye::Page::Page (this=0x6071b0, context=0x607750, width=300, height=300,
genome_display_length=1000) at /home/yangxi/projects/GenoEye/src/geno_eye/Page.cpp:29
#3 0x00000000004016b8 in geno_eye::__tester__::run (this=0x7fffffffe1c8)
at /home/yangxi/projects/GenoEye/t/t_page.cpp:15
#4 0x00000000004015d1 in main () at /home/yangxi/projects/GenoEye/t/t_page.cpp:36
(gdb) c
Continuing.
Hardware watchpoint 5: -location frame->genome_scale.frame_width
Old value = 240
New value = 3.1228427039313504e-317
_dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:40
40 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) bt
#0 _dl_runtime_resolve () at ../sysdeps/x86_64/dl-trampoline.S:40
#1 0x00007ffff7b93dd0 in geno_eye::Page::build_default_frame (this=0x6071b0, genome_display_length=1000)
at /home/yangxi/projects/GenoEye/src/geno_eye/Page.cpp:127
#2 0x00007ffff7b93cc1 in geno_eye::Page::Page (this=0x6071b0, context=0x607750, width=300, height=300,
genome_display_length=1000) at /home/yangxi/projects/GenoEye/src/geno_eye/Page.cpp:29
#3 0x00000000004016b8 in geno_eye::__tester__::run (this=0x7fffffffe1c8)
at /home/yangxi/projects/GenoEye/t/t_page.cpp:15
#4 0x00000000004015d1 in main () at /home/yangxi/projects/GenoEye/t/t_page.cpp:36
The two old values are the correct values for that two member variables. This write operation is happened before executing the = function of boost intrusive_ptr, as I pressed tens of "next", and the code is still in file dl-trampoline.S.
(gdb) n
41 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
42 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
43 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
44 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
45 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
46 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
47 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
48 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
49 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
50 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
51 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
52 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
53 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
54 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
56 in ../sysdeps/x86_64/dl-trampoline.S
(gdb) n
boost::intrusive_ptr<geno_eye::Frame>::operator= (this=0x6071b0, rhs=0x3e8)
at /usr/include/boost/smart_ptr/intrusive_ptr.hpp:134
134 {
What is dl-trampoline.S ? Why it silently write on the memory of my object?
In addition of that, I also run valgrind:
$ valgrind ./t_page
However, instead of invalid write, it reports invalid read to that object, which is happened after the object creation is finished.

This is caused by an reference-to-stack bug.
Object genome_scale holds two references to two member variables of frame object. When I reconstruct my code, it accidentally reference to two stack variables...
So, maybe I should avoid the use of reference types in this situation, as you can easily provide stack stuffs to them and don't get any warns.

Related

crashing for __cxxabiv1::__cxa_pure_virtual () - vtable ptr to abstract base class?

I have a crash in application:
__cxxabiv1::__cxa_pure_virtual ()
I can understand
What is the meaning of a "pure virtual" call in a stack trace?
And according "1 Answer" below i can exercise a little test program:
1 #include <iostream>
2
3 class Base
4 {
5 public:
6 Base()
7 {
8 std::cout << "Base c'tor" << std::endl;
9 }
10
11 virtual ~Base()
12 {
13 std::cout << "Base d'tor" << std::endl;
14 }
15
16 };
17
18 class Derived : public Base
19 {
20 public:
21 Derived()
22 : Base()
23 {
24 std::cout << "Derived c'tor" << std::endl;
25 }
26
27 ~Derived()
28 {
29 std::cout << "Derived d'tor" << std::endl;
30 }
31 };
32
33 int
34 main(
35 int,
36 char**)
37 {
38 {
39 Derived d;
40 }
41 return 0;
42 }
compile with:
g++ -g3 -O0 -o test test.cc
create gdb batch script:
break 8
command
p this
x/10xg this
x/10xg (long)*this
cont
end
break 13
command
p this
x/10xg this
x/10xg (long)*this
cont
end
break 24
command
p this
x/10xg this
x/10xg (long)*this
cont
end
break 29
command
p this
x/10xg this
x/10xg (long)*this
cont
end
run
and run:
frank#frank-PC:~$ gdb ./test < gdb.bat |c++filt
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...done.
(gdb) Breakpoint 1 at 0x400b72: file test.cc, line 8.
(gdb) >>>>>(gdb) Breakpoint 2 at 0x400baa: file test.cc, line 13.
(gdb) >>>>>(gdb) Breakpoint 3 at 0x400c29: file test.cc, line 24.
(gdb) >>>>>(gdb) Breakpoint 4 at 0x400c81: file test.cc, line 29.
(gdb) >>>>>(gdb) Starting program: /home/frank/test
Breakpoint 1, Base::Base (this=0x7fffffffdab0) at test.cc:8
8 std::cout << "Base c'tor" << std::endl;
$1 = (Base * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400df8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
0x400e28 <typeinfo name for Derived+8>: 0x0000000000000000 0x0000000000602090
0x400e38 <typeinfo for Base+8>: 0x0000000000400e40 0x0000006573614234
Base c'tor
Breakpoint 3, Derived::Derived (this=0x7fffffffdab0) at test.cc:24
24 std::cout << "Derived c'tor" << std::endl;
$2 = (Derived * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400dd8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400dd8 <vtable for Derived+16>: 0x0000000000400c68 0x0000000000400ce2
0x400de8 <vtable for Base>: 0x0000000000000000 0x0000000000400e30
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
Derived c'tor
Breakpoint 4, Derived::~Derived (this=0x7fffffffdab0, __in_chrg=<optimized out>) at test.cc:29
29 std::cout << "Derived d'tor" << std::endl;
$3 = (Derived * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400dd8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400dd8 <vtable for Derived+16>: 0x0000000000400c68 0x0000000000400ce2
0x400de8 <vtable for Base>: 0x0000000000000000 0x0000000000400e30
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
Derived d'tor
Breakpoint 2, Base::~Base (this=0x7fffffffdab0, __in_chrg=<optimized out>) at test.cc:13
13 std::cout << "Base d'tor" << std::endl;
$4 = (Base * const) 0x7fffffffdab0
0x7fffffffdab0: 0x0000000000400df8 0x597870ad9bc42900
0x7fffffffdac0: 0x0000000000400d10 0x00007ffff7495830
0x7fffffffdad0: 0x0000000000000000 0x00007fffffffdba8
0x7fffffffdae0: 0x00000001ffffdbb8 0x0000000000400ab6
0x7fffffffdaf0: 0x0000000000000000 0x9e98039144430dd4
0x400df8 <vtable for Base+16>: 0x0000000000400b92 0x0000000000400bde
0x400e08 <typeinfo for Derived>: 0x0000000000602200 0x0000000000400e20
0x400e18 <typeinfo for Derived+16>: 0x0000000000400e30 0x6465766972654437
0x400e28 <typeinfo name for Derived+8>: 0x0000000000000000 0x0000000000602090
0x400e38 <typeinfo for Base+8>: 0x0000000000400e40 0x0000006573614234
Base d'tor
[Inferior 1 (process 4962) exited normally]
(gdb) (gdb) quit
But the stacktrace for my real application (not the little demo above) hits:
__cxxabiv1::__cxa_pure_virtual ()
while the last d'tor i see on the call stack is the derived class.
So is this an indicator, that memory object was already free'd and re-used again for some other object instance?
How can that be? Is such done by the compiler for intermediate work?
Yes. Typically, a constructor first sets the vtable pointer to its own class's vtable. Then, when the derived class's constructor runs, it overwrites the vtable pointer with its own.
This achieves exactly the behavior that the C++ standard requires, that calls to virtual functions during the execution of constructors (and destructors; they reverse these assignments) treat the objects as having the dynamic type of the constructor, not the actual complete object. And in the case of pure virtual functions, the behavior is undefined; compilers typically insert this diagnostic stub in the vtable.

Skip innermost frames in backtrace

I would like to create a backtrace in gdb (in a script). The command bt 2 prints only the 2 innermost frames, while bt -2 prints only the 2 outermost frames.
What I'd like to do is to skip the 2 innermost frames, and show all outer frames. I've tried
up 2
bt
(and similarly up-silently, frame, select-frame), but it doesn't affect the output of bt. To be clear, I want to get rid of the first to lines in this output:
#0 0x0000003167e0f33e in waitpid () from /lib64/libpthread.so.0
#1 0x00007f2779835de8 in print_trace() () at /path/to/MyAnalysis.cxx:385
#2 0x00007f2779836ec9 in MyAnalysis::getHistHolder(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) () at /path/to/MyAnalysis.cxx:409
#3 0x00007f27798374aa in MyAnalysis::execute() () at /path/to/MyAnalysis.cxx:599
#4 0x00007f2783a9670f in EL::Worker::algsExecute() () from /blah/lib/libEventLoop.so
...
Any way to do this?
Calling return twice seems to work, but then the application is left in an invalid state afterwards, so I can't use it.
Your argument to "bt" depends on current number of frames present. Probably this can also be done in gdb directly (not sure), but this python script does exactly this:
import gdb
class TopBt (gdb.Command):
""" tbt n Shows backtrace for top n frames """
def __init__ (self):
super(TopBt, self).__init__ ("tbt", gdb.COMMAND_DATA)
def framecount():
n = 0
f = gdb.newest_frame()
while f:
n = n + 1
f = f.older()
return n
def invoke (self, arg, from_tty):
top = int(arg[0])
btarg = -(TopBt.framecount() - top)
if btarg < 0:
gdb.execute("bt " + str(btarg))
TopBt()
Save this to some file (tbt.py), source it in gdb (source tbt.py). Now you have new command tbt. tbt N will print backtrace for all but top N frames.
If it's ok for the stack to be capped at some pre-determined length, you can provide an explicit long list, like this for up to 40 frames starting at frame 4:
frame apply level 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 43 -q frame
Frame numbers beyond what's available appear to be ignored.

GDB tracing: No current trace frame

I am trying GDB tracepoints, but I can't get any data. I start gdbserver as following:
$ gdbserver :1234 ./a.out
Process ./a.out created; pid = 13610
Listening on port 1234
I then use the following commands on my client:
$ gdb ./a.out
...
Reading symbols from /home/simark/src/test/a.out...done.
(gdb) target remote :1234
Remote debugging using :1234
Reading symbols from /lib64/ld-linux-x86-64.so.2...done.
Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.15.so...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007ffff7ddb6c0 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) l
1 #include <stdio.h>
2 int foo(int a, int b) {
3 return a + b + b;
4 }
5
6 int main() {
7 int n = foo(33, 4);
8 printf("%d\n", n);
9 return 0;
10 }
(gdb) trace 3
Tracepoint 1 at 0x400526: file test.c, line 3.
(gdb) b 9
Breakpoint 2 at 0x400563: file test.c, line 9.
(gdb) actions 1
Enter actions for tracepoint 1, one per line.
End with a line saying just "end".
>collect $regs,$args
>end
(gdb) tstart
(gdb) c
Continuing.
Breakpoint 2, main () at test.c:9
9 return 0;
(gdb) tstop
(gdb) tdump
warning: No current trace frame.
(gdb)
According to the examples I saw on the web, I should have one event, because control passed over my tracepoint. Any ideas why I get no data?
According to the examples I saw on the web, I should have one event, because control passed over my tracepoint.
You forgot to do tfind start before doing tdump. From help tdump:
Print everything collected at the current tracepoint.
But you are not stopped at any tracepoint, you are stopped at breakpoint#2.
The tfind start selects the first trace frame in the trace buffer.

Why watchpoint doesn't effect?

I am studying the watchpoint of GDB. I write a simple test code as following:
int main(int argc, char **argv)
{
int x = 30;
int y = 10;
x = y;
return 0;
}
I build it via gcc -g -o wt watch.c. And then I started gdb and did following experiment:
lihacker#lihacker-laptop:~/mySrc$ gdb ./wt
GNU gdb (GDB) 7.3
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/lihacker/mySrc/wt...done.
(gdb) b main
Breakpoint 1 at 0x80483a5: file watch.c, line 5.
(gdb) run
Starting program: /home/lihacker/mySrc/wt
Breakpoint 1, main (argc=<optimized out>, argv=<optimized out>) at watch.c:5
5 int x = 30;
(gdb) watch x
Hardware watchpoint 2: x
(gdb) c
Continuing.
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0xb7e83775 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb)
In my test codes, the variable "x" is changed, but gdb doesn't stop then.
Why the watchpoint doesn't effect here? Thanks a lot.
This:
Breakpoint 1, main (argc=<optimized out>, argv=<optimized out>) at watch.c:5
suggests that you used -O2 or some such flag when building the test. Try building with -O0 (which will explicitly disable optimization).
Even then, there is a glitch (a buglet) in GDB. Here is what I see:
(gdb) b main
Breakpoint 3 at 0x80483ba: file t.c, line 3.
(gdb) r
Breakpoint 3, main (argc=1, argv=0xffffca94) at t.c:3
3 int x = 30;
(gdb) watch x
Hardware watchpoint 4: x
(gdb) c
Hardware watchpoint 4: x
Old value = 0
New value = 10
main (argc=1, argv=0xffffca94) at t.c:8
8 return 0;
(gdb) c
Watchpoint 4 deleted because the program has left the block in
which its expression is valid.
0xf7e7cbd6 in __libc_start_main () from /lib32/libc.so.6
This can't be right: the value of x changes from 30 to 10, not from 0 to 10.
If I set the breakpoint on the very first instruction of main, then it works as expected:
(gdb) b *main
Breakpoint 1 at 0x80483b4: file t.c, line 2.
(gdb) r
Breakpoint 1, main (argc=1, argv=0xffffca94) at t.c:2
2 {
(gdb) watch x
Hardware watchpoint 2: x
(gdb) c
Hardware watchpoint 2: x
Old value = 0
New value = 30
main (argc=1, argv=0xffffca94) at t.c:4
4 int y = 10;
(gdb) c
Hardware watchpoint 2: x
Old value = 30
New value = 10
main (argc=1, argv=0xffffca94) at t.c:8
8 return 0;
(gdb) c
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0xf7e7cbd6 in __libc_start_main () from /lib32/libc.so.6

gdb: Meaning of tstart error "You can't do that when your target is `exec'"

I would like to record the value of a local variable, t, each time that the program reaches a certain line. Accordingly, I tried:
(gdb) trace stoer_wagner_min_cut.hpp :197
Tracepoint 1 at 0x4123a0: file ./boost/graph/stoer_wagner_min_cut.hpp, line 197.
(gdb) actions
Enter actions for tracepoint 1, one per line.
End with a line saying just "end".
> collect t
> end
(gdb) tstart
You can't do that when your target is `exec'
(gdb) break main
Breakpoint 2 at 0x401448: file time_stoer_wagner.cpp, line 50.
(gdb) run
Starting program: C:\Users\Daniel\Documents\projects\stoer_wagner_min_cut/time_stoer_wagner.exe
[New Thread 3908.0x39c]
Breakpoint 2, main () at time_stoer_wagner.cpp:50
50 std::ifstream ifs("prgen_500_50_2.txt");
(gdb) tstart
You can't do that when your target is `child'
but the error messages "You can't do that when your target is `exec'" and "You can't do that when your target is `child'" are not helpful to me. What do these errors mean?
The tracepoint facility is currently available only for remote targets.
You should be able to perform the tracing experiment you desire by using gdbserver. Example:
$ gdbserver :0 ./a.out
Process ./a.out created; pid = 21838
Listening on port 51596
In another window:
$ gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) target remote :51596
0x00007fa76ec3fa60 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) list foo
1 int foo(int x)
2 {
3 return x;
4 }
5
6 int main()
7 {
8 for(int i = 0; i < 10; ++i)
9 foo(i);
10 return 0;
11 }
(gdb) trace 3
Tracepoint 1 at 0x40053f: file t.c, line 3.
(gdb) actions
> collect x
> end
(gdb) c
Tracing experiment now collects the data ...