如何调试非确定性内存损坏?

时间:2017-03-11 22:25:03

标签: c++ c debugging memory-corruption

我有一个不确定的内存损坏问题。因为它并不总是相同的地址,并且很少发生,所以我不能 while (my $line = <$fh>) { chomp $line; #remove square brackets $line=~s/[\[\]]//; while($line =~m/((\s*(.*))\/((.*)\s+))/gi) { $word=$1; $tag=$2; #remove whitespace from left and right of string $word=~ s/^\s+|\s+$//g; $tag=~ s/^\s+|\s+$//g; $tags{$tag}++; $tagHash{$tag}{$word}++; } } foreach my $str (sort keys %tagHash) { foreach my $s (keys %{$tagHash{$str}} ) { print "tags:$str - word: $s-> $tagHash{$str}{$s}\n"; } } watchpoint

问题是我的程序中A点和B点之间的值发生了变化。唯一应该改变它的是C点,它不会在那个时间运行(至少不会遇到意外修改的特定实例)。

我想做的事情就像gdb点A处的值一样,如果它被修改并且在C点的故意修改周围再次受到保护,机器将陷入陷阱。当然,{ {1}}并不意味着字面意思,因为我需要它来处理单词粒度。

只需用mprotect手动指向A点就太费力了,问题的频率只有千分之一左右。

理想情况下,我想在修改它的点上进行堆栈跟踪。

有什么想法吗?

更新:我刚刚发现mprotect http://rr-project.org/,这个工具据称可以确定&#34;确定&#34;非决定论问题。我准备好了。

更新2:这是一次短途旅行:

gdb

2 个答案:

答案 0 :(得分:3)

您遇到了未定义的行为,并且它正在其他地方引起,调试这非常困难。

由于您显然是在Linux上,请使用valgrind,它会对您有所帮助。如果您不在Linux或( OS X也受valgrind 支持),请为您的系统搜索等效的内存错误检测软件。

答案 1 :(得分:2)

我发现用你知道的脚本语言(在我的例子中,gdb)编写Ruby脚本并不困难。这减少了学习如何制作正确的gdb脚本的需要!

目标程序和脚本之间的API是目标程序有一个名为my_breakpoint的空白函数,它接受一个机器字作为参数。调用my_breakpoint(1); my_breakpoint(addr);会在监视列表中添加一个地址,而常量2的相同内容会从监视列表中删除一个地址。

要使用此功能,您需要启动gdbserver 127.0.0.1:7117 myapp myargs,然后启动以下脚本。当脚本检测到问题时,它会与gdbserver完全断开连接,以便您可以将gdb的另一个实例与gdb -ex 'target remote 127.0.0.1:7117'重新连接,然后离开。

请注意,使用此类软件观察点时,极其的速度很慢;也许有一天这样的东西可以作为valgrind工具来实现。

#!/usr/bin/env ruby

system("rm -f /tmp/gdb_i /tmp/gdb_o");
system("mkfifo /tmp/gdb_i /tmp/gdb_o");
system("killall -w gdb");
system("gdb -ex 'target remote 127.0.0.1:7117' </tmp/gdb_i >/tmp/gdb_o &");

$fo = File.open("/tmp/gdb_i", "wb");
$fi = File.open("/tmp/gdb_o", "rb");

def gdb_put(l)
  $stderr.puts("gdb_out: #{l}");
  $fo.write((l + "\n"));
  $fo.flush;
end

gdb_put("b my_breakpoint");
gdb_put("set can-use-hw-watchpoints 0");
gdb_put("c");

$state = 0;
$watchpoint_ctr = 1; # start at 1 so the 1st watchpoint gets 2, etc. this is because the breakpoint gets 1.
$watchpoint_nr = {};

def gdb_got_my_breakpoint(x)
  $stderr.puts("my_breakpoint #{x}");

  if ((x == 1) || (x == 2))
    raise if ($state != 0);
    $state = x;
    gdb_put("c");
  else
    if ($state == 1)
      raise if ($watchpoint_nr[x].nil?.!);
      $watchpoint_nr[x] = ($watchpoint_ctr += 1);
      gdb_put("watch *#{x}");
    elsif ($state == 2)
      nr = $watchpoint_nr[x];
      if (nr.nil?)
        $stderr.puts("WARNING: ignoring delete request for watchpoint #{x} not previously established");
      else
        gdb_put("delete #{nr}");
        $watchpoint_nr.delete(x);
      end
    end
    $state = 0;
    gdb_put("info breakpoints");
    $stderr.puts("INFO: my current notion: #{$watchpoint_nr}");
    gdb_put("c");
  end
end

def gdb_got(l)
  t = l.split;

  if ((t[0] == "Breakpoint") && (t[2] == "my_breakpoint"))
    gdb_got_my_breakpoint(t[3][3..-2].to_i);
  end

  if (l.start_with?("Program received signal ") || l.start_with?("Watchpoint "))
    gdb_put("disconnect");
    gdb_put("q");
    sleep;
  end
end

while (l = $fi.gets)
  l = l.strip;

  $stderr.puts("gdb_inp: #{l}");

  gdb_got(l);
end
相关问题