看板 C_and_CPP 關於我們 聯絡資訊
來段程式好了 這個問題要分成內建type和自定義class 這兩個會有不同的結果 由於要讓違法的語法compile過,所以加上-fpermissive這個flag <狀況一: 自定義class> class aaa { public: void modify(int s){i=s;} void print()const{cout<<i<<endl;} private: int i=1; }; int main() { aaa const** aq; //老大 aaa* ap; //老二 const aaa ax; //老三 aq = &ap; //這是被禁止的,但是加上-fpermissive暫時編譯過 *aq = &ax; //由於*aq=ap,所以ap指向ax ap->modify(5566); //ax.i變成5566 !!! 執行期沒有掛 ax.print(); } <狀況二: 內建type> int const** q; int* p; const int x=1; q = &p; *q = &x; *p=5566; //x還是1並沒變5566,執行期沒有掛 <結論> 1.基於安全考量所以int **不能轉成int const ** (可以參考上篇po文) 2.自定義class的const物件用走漏洞的方式可以更改 3.內建type的const變數用走漏洞的方式改不動,我不知道為什麼,有請高手解釋 4.執行期都不會掛,執行期應該不會去檢查,這會影響效率 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.25.240.10 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1423407806.A.ADF.html ※ 編輯: RealJack (114.25.240.10), 02/08/2015 23:05:09 ※ 編輯: RealJack (114.25.240.10), 02/08/2015 23:08:27
purpose: 我有在 Windows 用 g++ 編譯試過,const int 剛好被放在 02/09 00:08
purpose: 唯讀記憶體,所以有碰過改完 Runtime 當掉的狀況。 02/09 00:09
purpose: 至於 x 還是 1 沒變 5566,那是編譯器在編譯時,就直接 02/09 00:10
purpose: 把值寫死成 1,他不會在 Runtime 重新讀取 x 的內容 02/09 00:10
RealJack: 我覺得還是有點問題,編譯會直接寫死應該只有巨集之類才 02/09 15:04
uranusjr: @RealJack 世界上有個技術叫最佳化 02/09 15:05
RealJack: 會發生,我把const全部去掉後發現內建type的值會改變 02/09 15:06
RealJack: 然後用objdump比較這兩個.o檔,發現組語都一樣 02/09 15:07
RealJack: http://ppt.cc/1SKb 02/09 15:07
RealJack: 這樣要如何解釋加const和沒有const的行為會不一樣呢? 02/09 15:08
dirkc: 其實改了,只是之後用到符號x的時候極可能會直接置換成常數1 02/09 15:36
dirkc: 改成int y=1;const int x=y;或volatile const int x=1; 02/09 15:37
dirkc: 就會看出一樓說的差別,因為會強制使用可讀寫位址存放x 02/09 15:38
dirkc: 編譯器也不會把符號x置換成常數1 02/09 15:38
dirkc: @RJ 你把x丟入函式(例如printf)再看組語就知道 02/09 15:42
dirkc: 丟x和丟*p是不同結果,因為x可能會直接被置換成常數 02/09 15:43
dirkc: const這個字在執行期沒有意義,執行後只看memory protection 02/09 15:55
dirkc: 本質上不是效率考量,精確說是根本不考量 02/09 15:56
purpose: http://imgur.com/a/36IQz/layout/blog 我跑的反組譯碼 02/09 18:12
RealJack: 我先研究一下好了...背後有很多些東西要釐清@@ 02/09 18:24
RealJack: 再請教一下要如何確定變數被放在唯讀的記憶體區塊,感謝! 02/09 18:25
purpose: http://i.imgur.com/CUAb5jf.png 我下中斷點看到 x 的 02/09 18:30
purpose: 位址後,這個 debugger 有提供記憶體分佈資訊,其中的 02/09 18:30
purpose: 00409000 起始位址這項目,它的存取欄位只有寫 R 就唯讀 02/09 18:31
dirkc: 通常要確定就是用debugger去看編譯後結果,像樓上的反組譯 02/10 09:53
dirkc: 顯示x存在0x409050,p則是用堆疊esp+1c的位址;然後現在os基 02/10 09:55
dirkc: 本上除了堆疊和堆積幾乎都是唯讀,也可以用debugger查詢 02/10 10:07
dirkc: 怎麼配是編譯器的決定,不過字面常數或全域const容易配唯讀 02/10 10:09
dirkc: 應該說怎麼配是編譯器的初稿,os的定案;編譯器決定位置,os可 02/10 10:16
dirkc: 決定rwx讀寫執行權限,也可能修改區塊基底位址(ASLR) 02/10 10:17
dirkc: (這裡說的編譯器指的是同時有編譯,組譯,連結功能的程式) 02/10 10:25
dirkc: 有點想說通常寫程式不用去探究這些;今天就是因為某種程度 02/10 10:40
dirkc: 而言欺騙了編譯器(先告訴它const而後又要去改),既然越過了 02/10 10:41
dirkc: 編譯器,就需要更底層的資訊來解釋發生的現象 02/10 10:42