[問題] 請問local變數在離開stack後為何能存取

作者: Keitaro (動き出す時間...)   2021-04-01 21:54:38
開發平台(Platform): (Ex: Win10, Linux, ...)
win10/debian
編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
VC2008/gcc
程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔)
#include <stdio.h>
struct StructB
{
int m_nB;
StructB()
{
m_nB = 0;
}
~StructB()
{
printf("~StructB()\n");
}
};
struct StructA
{
StructA()
{
m_pB = NULL;
}
StructB *m_pB;
};
void foo(StructA &p_stA)
{
StructB stB;
stB.m_nB = 1;
p_stA.m_pB = &stB;
}
int main()
{
StructA stA;
foo(stA);
printf("stA.m_pB->m_nB = %d\n", stA.m_pB->m_nB);
printf("stA.m_pB->m_nB = %d\n", stA.m_pB->m_nB); // 連續兩次看結果
return 0;
}
補充說明(Supplement):
今天工作上我看到project code有很明顯的問題如下.
有一個struct其中一個member是一個pointer,
這個struct產生一個member object放在一個class裡面.
而我尋找這個pointer並沒有任何地方去new物件出來,
而是直接在一個function裡面產生一個local變數,
然後把local變數的位址設定給這個pointer.
問題來了, 設定local變數給這個struct的pointer,
然後離開這個function回到上一層stack, local變數不就free掉了嗎?
再去存取這個struct pointer不是應該就會出問題?
但結果沒有, 我用VC debug看程式竟然還能存取到正確的值.
這讓我對以前變數lifecycle學習產生了質疑,
因此我直接寫了上方簡單的程式碼來驗證這件事.
我分別用VC以及gcc在win10/debian底下去執行上面的程式碼,
神奇的事發生了
win10:
第一次printf看到印出的值正確為1, 第二次變為-2.
debain:
兩次都為1.
我確認StructB的解構式已經"先"印出來才印出數值,
為何被free的變數還能存取到他的數值呢?
請版上先進指教, 謝謝。
作者: nh60211as   2021-04-01 21:57:00
你運氣好(不好)
作者: LPH66 (-6.2598534e+18f)   2021-04-01 21:57:00
就只是單純當時分給他的位置還沒人來而已
作者: Lipraxde (Lipraxde)   2021-04-01 21:58:00
寫出 UB 就是爽,一直寫 UB 一直爽是 undefined behavior 沒錯,不過你這個例子,compiler 應該會報 warning / error 吧?
作者: ando5566 (風雲變色)   2021-04-01 22:56:00
並沒有free掉 ,stack pointer 和base pointer回到上一個function的狀態,你在callee之後宣蹷@個大的陣列即可把stack memory洗掉。
作者: Lipraxde (Lipraxde)   2021-04-01 23:57:00
差別是放在 stack 上還說 heap 上如果有 address sanitizer 可以用的話開起來應該也可以在執行時跳出錯誤
作者: sarafciel (Cattuz)   2021-04-02 00:19:00
嚴格說起來是你的rsp/rbp改掉的時候就算release了只是release不代表你的local variable值一定會改變
作者: b0920075 (Void)   2021-04-02 00:33:00
有沒有洗掉不是很重要,就算他沒被洗掉你也不應該去用,誰知道等下還會不會留著
作者: sarafciel (Cattuz)   2021-04-02 01:52:00
你對free跟lifecycle消滅的定義是什麼呢?是執行期當你access這塊記憶體時 程式應該要報錯嗎?
作者: Lipraxde (Lipraxde)   2021-04-02 02:31:00
Compiler 沒偷做什麼,頂多說是偷懶沒把 stack 刷掉
作者: a1u1usul3 (Q-Max)   2021-04-02 04:14:00
為什麼刪除的檔案還有機會找回來?因為剛好沒被洗掉。為什麼上一個function裡面local variable還在?因為剛好沒被洗掉compiler沒有偷做什麼,他只是不再使用這個地方而已。既然已經不再使用這裡也就不用特地清成0了
作者: ando5566 (風雲變色)   2021-04-02 08:17:00
先執行destructor ,再離開當下function (做stk /bsp restore) ,最後pop pc+1 與jump ;destruct內沒有清除datamember的行為,對吧
作者: LPH66 (-6.2598534e+18f)   2021-04-02 13:02:00
或者應該反過來說, compiler 就是沒偷做什麼才會還能讓你偷偷回去挖裡面原來放了些什麼東西ie.這裡沒照規矩做事的反而是程式去存取已經結束生命的變數
作者: unmolk (UJ)   2021-04-03 03:43:00
在這串學到許多+1 謝謝板上各位大大!
作者: steve1012 (steve)   2021-04-06 03:11:00
特別去清掉會造成performance hit 沒甚麼必要

Links booklink

Contact Us: admin [ a t ] ucptt.com