2009-09-02 55 views
1

當我的C++程序試圖將一些.png圖像寫入目錄時,會發生一些溢出運行時錯誤。將圖像寫入目錄失敗

將圖像寫入的目錄作爲命令行參數給出。該程序使用gcc -ggdb3 -O3進行編譯。奇怪的是,如果我重新運行目錄時將該目錄更改爲另一個目錄,或者如果我沒有優化編譯我的程序,該錯誤就會消失。我很困惑。即使我可以獲取非優化可執行文件生成的圖像或其他目錄,但我懷疑結果是否可靠,因爲優化後的可執行文件可能存在運行時錯誤?或者有可能優化產生易出錯的可執行文件?任何人都可以解釋?

我想,因爲它是用gcc -ggdb3 -O3編譯調試優化的可執行文件,但這個地方它會產生溢出錯誤,不給的源代碼,這是我不能得到一些線索:

(GDB)BT

#0 0x00007fbd29573fb5在從/lib/libc.so.6

#2從/lib/libc.so.6

#1 0x00007fbd29575bc3在中止()加註() 0x00007fbd295b3228在? ()從/lib/libc.so.6

#3 0x00007fbd296402c7在從/lib/libc.so.6

#4 0x00007fbd2963e170在__chk_fail()從打開/lib/libc.so __fortify_fail()。 6

#5 0x00007fbd2963d519 in ?? ()從/lib/libc.so.6

#6 0x00007fbd295b7426在_IO_default_xsputn()從/lib/libc.so.6

#7 0x00007fbd29586fdb在vfprintf()從打開/lib/libc.so。 6

#8 0x00007fbd2963d5b9在從/lib/libc.so.6

#10 0x0000000000408695在主從/lib/libc.so.6

#9 0x00007fbd2963d500在__sprintf_chk()__vsprintf_chk() ()

(GDB)的F 10

#10 0x0000000000408695在main()

當前語言:汽車;目前在彙編

(GDB)名單

1 /build/buildd/glibc-2.9/build-tree/amd64-libc/csu/crtn.S:沒有這樣的文件或目錄。

在/build/buildd/glibc-2.9/build-tree/amd64-libc/csu/crtn.S

(GDB)

我不知道如果運行時的輸出錯誤可能有助於分析問題。如果可以,這裏是錯誤消息的樣子,有點大長雖:

*檢測緩衝區溢出*:/順/家/添/科研/荒誕/ absurditylinux/binio21 /發行/荒謬終止

[新主題0x7fbd2acd9740(LWP 2347)]

=======回溯:=========

/lib/libc.so.6( __fortify_fail + 0x37)[0x7fbd296402c7]

/lib/libc.so.6[0x7fbd2963e170]

/lib/libc.so.6[0x7fbd2963d519]

/lib/libc.so.6(_IO_default_xsputn+0x96)[0x7fbd295b7426]

/lib/libc.so.6(_IO_vfprintf+0x63b)[0x7fbd29586fdb]

/lib/libc.so.6(__vsprintf_chk+0x99)[0x7fbd2963d5b9]

/lib/libc.so.6 (__sprintf_chk + 0x80)[0x7fbd2963d500]

/順/家/添/科研/荒誕/ absurditylinux/binio21 /發行/荒謬[0x408695]

/lib/libc.so.6(__libc_start_main+0xe6)[0x7fbd2955f5a6]

/順/家用/恬/科研/荒誕/ absurditylinux/binio21 /發行/荒謬[0x4045d9]

=======存儲器映射:======

00400000-00471000 R-XP 00000000 00:39 52084894/cis/home/tim/research/absurdity/absurditylinux/binio21/release/absurdity

00671000-00672000 [R - P 00071000 00:39 52084894 /順/家/添/科研/荒誕/ absurditylinux/binio21 /發行/荒謬

00672000-00673000 RW-P 00072000 00:39 52084894 /順/家/添/研究/荒誕/ absurditylinux/binio21 /釋放/荒謬

00673000-00675000 RW-p 00673000 00:00 0

00943000-00964000 RW-p 00943000 00:00 0 [堆]

7fbd273f7000-7fbd29339000 rw-p 7fbd273f7000 00:00 0

7fbd29339000-7fbd29340000 R-XP 00000000 08:01 35791448 /lib/librt-2.9.so

7fbd29340000-7fbd2953f000 --- p 00007000 08:01 35791448 /lib/librt-2.9.so

7fbd2953f000 -7fbd29540000 - [R - p 00006000 08:01 35791448 /lib/librt-2.9.so

7fbd29540000-7fbd29541000 RW-p 08:01 00007000 35791448 /lib/librt-2.9.so

7fbd29541000-7fbd296a9000ř -xp 00000000 08:01 35791428 /lib/libc-2.9。所以

7fbd296a9000-7fbd298a9000 --- p 00168000 08:01 35791428 /lib/libc-2.9.so

7fbd298a9000-7fbd298ad000 [R - P 00168000 08:01 35791428 /lib/libc-2.9.so

7fbd298ad000-7fbd298ae000 RW-p 08:01 0016c000 35791428 /lib/libc-2.9.so

7fbd298ae000-7fbd298b3000 RW-p 7fbd298ae000 00:00 0

7fbd298b3000-7fbd298c9000 R-XP 00000000 08: 01 35790870 /lib/libgcc_s.so.1

7fbd298c9000-7fbd29ac9000 --- p 00016000 08:01 35790870 /lib/libgcc_s.so.1

7fbd29ac9000-7fbd29aca000 - [R - P 00016000 08:01 35790870 /lib/libgcc_s.so.1

7fbd29aca000-7fbd29acb000 RW-p 08:01 00017000 35790870 /lib/libgcc_s.so.1

7fbd29acb000-7fbd29ad3000 R-XP 00000000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29ad3000-7fbd29cd2000 --- p 00008000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29cd2000-7fbd29cd3000 - [R - P 00007000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29cd3000-7fbd29cd4000 RW-P 08:01 00008000 71705955/usr/lib中/ libgomp。 so.1.0.0

7fbd29cd4000-7fbd29d58000 R-XP 00000000 08:01 35791436 /lib/libm-2.9.so

7fbd29d58000-7fbd29f57000 --- p 00084000 08:01 35791436 /lib/libm-2.9 .so

7fbd29f57000-7fbd29f58000 r - p 00083000 08:01 35791436 /lib/libm-2.9.so

7fbd29f58000-7fbd29f59000 RW-P 08:01 00084000 35791436 /lib/libm-2.9.so

7fbd29f59000-7fbd2a04a000 R-XP 00000000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a04a000-7fbd2a24a000 --- p 000f1000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a24a000-7fbd2a251000 - [R - p 000f1000 08:01 71704918/usr/lib中/ ++的libstdc .so.6.0.10

7fbd2a251000-7fbd2a253000 rw-p 000f8000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a253000-7fbd2a266000 RW-P 7fbd2a253000 00:00 0

7fbd2a266000-7fbd2a27d000 R-XP 00000000 08:01 35791446 /lib/libpthread-2.9.so

7fbd2a27d000-7fbd2a47c000 --- p 00017000 08:01 35791446 /lib/libpthread-2.9.so

7fbd2a47c000-7fbd2a47d000 [R - p 00016000 08:01 35791446 /lib/libpthread-2.9。如此接收

7fbd2a47d000-7fbd2a47e000 RW-P 08:01 00017000 35791446 /lib/libpthread-2.9.so

7fbd2a47e000-7fbd2a482000 RW-P 7fbd2a47e000 00:00 0

7F

程序信號SIGABRT,中止。

[切換主題0x7fbd2acd9740(LWP 2347)]

在加薪()從/lib/libc.so.6

0x00007fbd29573fb5非常感謝您的幫助!

感謝和問候!


@@ UPDATE @@: 你們是對的!我增加了char數組的長文件名的大小,現在很好!

可執行文件是/ cis/home/tim/research/absurdity/absurditylinux/binio21/release/absurdity。不起作用的目錄被指定爲命令行參數--result-path = ../results1/FrancContinuity1/noise0/train-imgs,它存儲在下面的global.result_path中。

你能告訴我你是如何懷疑這是你提到的問題嗎? __sprintf_chk()和__vsprintf_chk()總是由sprintf()調用?

這是代碼。

1部分:

 char filename[50]; 
     sprintf(filename, "%s/%d_%d.png", global.result_path, train_samples[n].label, train_samples[n].label==1 ? ++nb_pos : ++nb_neg); 
     train_samples[n].write_png(filename); 

2部分:

class Global { //parameters of program 
public: 
    int niceness; //The process scheduling priority 
    int random_seed; //The seed for the random sequence used in the computation 
    char result_path[1024]; //Where to store the generated results (images, logs, etc.) 
... 
} 

Global global; 
+0

你有一些可用的代碼。在我看來,你對sprintf調用的參數有問題。就像你打印的字符串太小一樣? – Matt 2009-09-03 00:00:26

+1

餓...需要密碼! – count0 2009-09-03 00:05:44

+0

謝謝!請在原始帖子末尾查看我的修改。 – Tim 2009-09-03 00:30:37

回答

3

有多長目錄名稱,多長時間在緩衝你試圖將其存儲在?你沒有給我們太多的東西繼續......如何顯示一些代碼?也許是在main()的某處調用sprintf ,並且涉及到任何變量的聲明?

編輯:它肯定看起來像文件名需要是一個更大的陣列,給定您的輸入目錄 和您追加它的文件名!快速修復:嘗試將它聲明爲1500個字符而不是50個。更好的解決方法:因爲您使用的是C++,請查看std :: string和ostringstream類,它們將自行調整大小以防止緩衝區溢出。

要回答你的後續問題:

在結果路徑的「../」不應該擴大到絕對路徑。

基於「緩衝區溢出」消息和gdb回溯中的最後幾行,我預測sprintf()涉及到的是一個幸運的猜測。我對glibc內部並不熟悉,但是__sprintf_chk()__vsprintf_chk()是sprintf()的緩衝區溢出檢查變體?

+0

謝謝!請在原始帖子末尾查看我的更新。 – Tim 2009-09-03 00:31:13

+0

謝謝!有點好奇,爲什麼沒有優化的可執行文件運行良好,沒有報告緩衝區溢出? – Tim 2009-09-03 01:00:09

+0

@Tim:這個錯誤導致了所謂的「未定義的行爲」 - 意思是:它可能會崩潰,它可能正常工作,它可能會導致惡魔飛出你的鼻子。編譯器可能會重新排列優化版本中的數據佈局,因此當您溢出緩衝區時,它會破壞其他內容,導致您看到的錯誤消息。 – 2009-09-03 01:21:48

1

那麼你使用sprintf打印到緩衝區'filename [50]',當然這個長度是50。現在,您正在打印的字符串是一個1024字節的緩衝區,這是一個潛在的問題。當global.result_path超過50時會發生什麼情況(實際上甚至更少,因爲您還在打印整數),那麼會發生溢出。

嘗試使用C++的std :: string和std :: stringstream的,即:

//Part 1: 

std::stringstream ss; 
ss << global.result_path << /* other data */; 
train_samples[n].write_png(ss.str().c_str()); 

//Part 2: 

class Global 
{ 
    std::string result_path; 
    ... 
} 

隨着你永遠不用擔心溢出的緩衝區字符或任何其他醜惡的東西上面的代碼。

2

我很久以前就養成了到處使用snprintf的習慣。學會喜歡它。它可能仍然無法寫入正確的文件,但至少它不會留下安全漏洞。

再經過你開始想知道爲什麼你的程序創建一個名爲文件"this_is_a_long_file_na"你可以回去,並修復它要麼使用的PATH_MAX緩衝區或動態大小的malloc分配的緩衝區。如果緩衝區需要更大,snprintf將幫助您找到合適的大小。

或者你可以切換到C++並使用std :: string。

+0

對於PATH_MAX引用+1並提到動態分配或std :: string肯定會更好 – 2009-09-03 02:14:50

1

result_path太小。

只需將result_path更改爲1024.某些系統具有已定義的宏MAX_PATH。 我也會將sprintf更改爲snprintf,其大小爲sizeof(result_path)。

snprintf()函數就像sprintf()一樣,只是給出了緩衝區的長度。這可以防止緩衝區溢出。

返回值是寫入的字符數。如果由於buff_size限制導致輸出被截斷,那麼返回值是如果有足夠空間可用的話將被寫入最終字符串的字符數(不包括結尾'\ 0')。

我怎麼知道你有一個sprintf的問題是回溯。

(gdb) bt 

#0 0x00007fbd29573fb5 in raise() from /lib/libc.so.6 

#1 0x00007fbd29575bc3 in abort() from /lib/libc.so.6 

#2 0x00007fbd295b3228 in ??() from /lib/libc.so.6 

#3 0x00007fbd296402c7 in __fortify_fail() from /lib/libc.so.6 

#4 0x00007fbd2963e170 in __chk_fail() from /lib/libc.so.6 

#5 0x00007fbd2963d519 in ??() from /lib/libc.so.6 

#6 0x00007fbd295b7426 in _IO_default_xsputn() from /lib/libc.so.6 

#7 0x00007fbd29586fdb in vfprintf() from /lib/libc.so.6 

#8 0x00007fbd2963d5b9 in __vsprintf_chk() from /lib/libc.so.6 

#9 0x00007fbd2963d500 in __sprintf_chk() from /lib/libc.so.6 

#10 0x0000000000408695 in main() 

即 你在你的代碼的功能爲主。和__sprintf_chk是它肚皮大的地方。 你必須調用sprintf。之後,它死了。所以我的猜測是你傳遞了糟糕的觀點。 sprintf可能死亡的唯一方法是緩衝區溢出。所以這是一個很好的假設,你打印的字符串太小了。使用snprintf和 它會更安全。然後您可以打印以調試結果。如果你已經這麼做了,你會直接看到緩衝區太小,因爲result_path會被截斷爲50個字符,並且程序不會崩潰(至少在這一點上)。