偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

比Printf高效1000倍!如何精準(zhǔn)捕捉C/C++野指針

開發(fā) 前端
在多線程程序中software watchpoint作用有限,因?yàn)槿绻粰z測的一段內(nèi)存被其它線程修改(就像本文中的示例)那么gdb可能捕捉不到該事件。

大家好,我是島主小風(fēng)哥。

內(nèi)存是C/C++程序員的好幫手,我們通常說C/C++程序性能更高其原因之一就在于可以自己來管理內(nèi)存,然而計(jì)算機(jī)科學(xué)中沒有任何一項(xiàng)技術(shù)可以包治百病,內(nèi)存問題也給C/C++程序員帶來無盡的煩惱。

野指針、數(shù)組越界、錯(cuò)誤的內(nèi)存分配或者釋放、多線程讀寫導(dǎo)致內(nèi)存被破壞等等,這些都會(huì)導(dǎo)致某段內(nèi)存中的數(shù)據(jù)被”無意“的破壞掉,這類bug通常很難定位,因?yàn)楫?dāng)程序開始表現(xiàn)異常時(shí)通常已經(jīng)距離真正出問題的地方很遠(yuǎn)了,常用的程序調(diào)試方法往往很難排查此類問題。

既然這類問題通常是由于內(nèi)存的讀寫造成,那么如果要是某一段內(nèi)存被修改或者讀取時(shí)我們能觀察到此事件就好了,幸運(yùn)的是這類技術(shù)已經(jīng)實(shí)現(xiàn)了。

圖片圖片


一段示例

在GDB中你可以通過添加watchpoint來觀察一段內(nèi)存,這段內(nèi)存被修改時(shí)程序?qū)?huì)停止,此時(shí)我們就能知道到底是哪行代碼對該內(nèi)存進(jìn)行了修改,這功能是不是很強(qiáng)大。

接下來我們用示例來講解一下,有這樣一段代碼:

#include <iostream>
#include <thread>
using namespace std;

// 線程修改變量值
void memory_write(int* value) {
  *value = 1;
}

int main()
{
    int a = 10;
    // 獲取局部變量a的地址
    int* c = &a;

    for (int i = 0; i < 100; i++) {
      a += i;
    }

    cout << a << endl;

    // 將變量a的地址傳遞到線程
    thread t(memory_write, c);
    t.join();

    return 0;
}

這段代碼非常簡單,創(chuàng)建局部變量a,然后獲取變量a的地址并賦值給指針c,此后對變量a進(jìn)行累加和,然后輸出a的值,此時(shí)a的值為4960。

假設(shè)此后你發(fā)現(xiàn)變量a的值竟然變?yōu)榱?,然而由于代碼非常復(fù)雜你并不知道到底是哪段代碼對變量a進(jìn)行修改,在上述代碼中我們利用線程a來模擬這個(gè)場景,線程獲取變量a的地址后對其進(jìn)行了修改,將其變?yōu)榱?,接下來我們利用調(diào)試工具gdb來定位到底是誰修改了變量a。

開始捕捉“肇事者”

對上述代碼進(jìn)行編譯,接下來利用gdb進(jìn)行調(diào)試,假設(shè)源文件的名稱是a.cc,編譯后的可執(zhí)行程序名字為a:

$ gdb a.out
(gdb) b a.cc:20
Breakpoint 1 at 0x400f23: file a.cc, line 20.
(gdb) r
Starting program: /bin/a
Breakpoint 1, main () at a.cc:20
20          cout << a << endl;

上述調(diào)試命令(b a.cc:20)表示我們在代碼的第20行加斷點(diǎn),當(dāng)程序運(yùn)行到這里后暫停,調(diào)試命令r表示開始運(yùn)行程序,可以看到運(yùn)行到第20行后暫停,此時(shí)我們查看一下變量a的地址:

(gdb) p &a
$1 = (int *) 0x7fffffffe508

可以看到,變量a位于內(nèi)存地址0x7fffffffe508,接下來重點(diǎn)來了,我們該怎樣告訴gdb讓它幫我們時(shí)刻監(jiān)測0x7fffffffe508這個(gè)內(nèi)存地址中的值有沒有被修改呢?很簡單:

(gdb) watch *(int*)0x7fffffffe508
Hardware watchpoint 2: *(int*)0x7fffffffe508

我們利用watch命令,讓gdb幫我們時(shí)刻監(jiān)測一段從0x7fffffffe508開始大小為4字節(jié)的內(nèi)存區(qū)域(假設(shè)int占據(jù)4字節(jié)),這就是watch *(int*)0x7fffffffe508這行指令的含義:

圖片圖片

除此之外上面gdb的輸出中還有一段值得注意:

Hardware watchpoint 2: *(int*)0x7fffffffe508

注意看,什么是Hardware watchpoint呢?先賣個(gè)關(guān)子,我們稍后聊,接下來我們運(yùn)行g(shù)db中的c命令,意思是continue,讓程序繼續(xù)運(yùn)行:

(gdb) c
Continuing.
4960

此時(shí)第20行執(zhí)行完畢并打印出了變量a的值4960,我們接著往下看:

[New Thread 0x7ffff6f5c700 (LWP 531823)]
[Switching to Thread 0x7ffff6f5c700 (LWP 531823)]
Hardware watchpoint 2: *(int*)0x7fffffffe508

Old value = 4960
New value = 1
memory_write (value=0x7fffffffe508) at a.cc:8
8       }
(gdb)

哈哈,gdb成功的捕捉到了是哪一行代碼修改了0x7fffffffe508這塊內(nèi)存,而且詳細(xì)的告訴我們所有信息,可以看到gdb打印出了這塊內(nèi)存之前保存的數(shù)據(jù)是數(shù)字4960,修改后的值為1,并且是在a.cc:8這里被修改的,而這里正是我們創(chuàng)建的線程對變量a進(jìn)行修改的地方,gdb成功的捕捉到了”肇事者“,原來是這個(gè)線程”無意“修改了變量a的值。

圖片圖片

是不是很神奇,那么這一切都是怎樣實(shí)現(xiàn)的呢?

watchpoint是怎樣實(shí)現(xiàn)的?

原來這一切都是CPU的功勞。

現(xiàn)代處理器中具有特殊的debug寄存器,x86處理器中是DR0到DR7寄存器,利用這些寄存器硬件可以持續(xù)檢測處理器發(fā)出的用于讀寫內(nèi)存的地址,更強(qiáng)大的是,不但硬件watchpoint可以檢查內(nèi)存地址,而且還是可以監(jiān)測到底是在讀內(nèi)存還是在寫內(nèi)存。

利用gdb中的rwatch命令你可以來監(jiān)測是否有代碼讀取了某段內(nèi)存;利用gdb中的awatch命令你可以來檢查是否有代碼修改了某段內(nèi)存;利用gdb中的watch命令你可以檢查對某段內(nèi)存是否有讀或者寫這兩種情況。

一旦硬件監(jiān)測到相應(yīng)事件,就會(huì)暫停程序的運(yùn)行并把控制權(quán)交給debugger,也就是這里的gdb,此時(shí)我們就可以對程序的狀態(tài)進(jìn)行詳細(xì)的查看了,這種硬件本身支持的調(diào)試能力就是剛才提到的Hardware watchpoint。

有hardware watchpoint就會(huì)有software watchpoint,當(dāng)硬件不支持hardware watchpoint時(shí)gdb會(huì)自動(dòng)切換到software watchpoint,此時(shí)你的程序每被執(zhí)行一條機(jī)器指令gdb就會(huì)查看相應(yīng)的事件是否發(fā)生,因此software watchpoint要遠(yuǎn)比hardware watchpoint慢,你可以利用gdb中的”set can-use-hw-watchpoints“命令來控制gdb該使用哪類watchpoint。

值得注意的是,在多線程程序中software watchpoint作用有限,因?yàn)槿绻粰z測的一段內(nèi)存被其它線程修改(就像本文中的示例)那么gdb可能捕捉不到該事件。

責(zé)任編輯:武曉燕 來源: 碼農(nóng)的荒島求生
相關(guān)推薦

2023-12-26 12:13:31

野指針C++編程

2010-01-28 13:57:19

C++指針基礎(chǔ)

2021-08-06 13:48:53

C語言野指針內(nèi)存

2021-12-21 15:31:10

C++語言指針

2010-01-26 13:42:28

C++指針

2011-04-11 11:09:50

this指針

2024-12-26 10:45:08

2024-05-15 16:01:04

C++編程開發(fā)

2014-01-24 09:49:01

C++指針

2021-10-27 16:27:20

C++指針操控

2011-07-12 13:01:00

CC++

2024-07-26 00:22:34

2021-06-10 08:51:57

C++指針聲明指針相關(guān)概念

2024-03-26 10:13:54

日志引擎SigLens

2024-04-10 12:14:36

C++指針算術(shù)運(yùn)算

2024-01-09 09:23:12

指針C++

2021-08-30 19:03:09

C++指針數(shù)據(jù)

2011-04-19 16:38:00

對象指針指針C++

2010-02-04 09:33:08

C++指針重載

2011-07-15 01:38:56

C++this指針
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號