[爆卦]Volatile C是什麼?優點缺點精華區懶人包

為什麼這篇Volatile C鄉民發文收入到精華區:因為在Volatile C這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者windows2k (程式宅 <囧>)看板C_and_CPP標題[問題] volat...


開發平台(Platform): (Ex: VC++, GCC, Linux, ...)
VC++/GCC/CLANG

額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
None

問題(Question):

volatile大概是C/C++最難了解的關鍵字之一
最近在看完這篇[How to zero a buffer](http://bit.ly/1wmpbys)產生的問題
在開啟最佳化之後,對照Assembly Code,所有的編譯器會捨棄掉stack上的memset。
不過如果照他的方式刻一個,會發現所有Compiler都會做清空的動作
static void
secure_memzero(void * p, size_t len)
{
volatile uint8_t * _p = p;

while (len--) *_p++ = 0;
}
不過中間有句話不太明瞭
The C standard states that accesses to volatile objects are part of the
unalterable observable behaviour — but it says nothing about accesses via
lvalue expressions with volatile types. Consequently a sufficiently
intelligent compiler can still optimize the buffer-zeroing away in this case
— it just has to prove that the object being accessed was not originally
defined as being volatile.
我不知道這段話是否正確,不過還沒找到Standard是否有類似的規定
如果這段話是正確的話,目前找到的
C11的[memset_s](http://bit.ly/1qJG7vv)
Windows的[SecureZeroMemory](http://bit.ly/1oC33rV)
作法都一樣,難道不怕被最佳化掉嘛
請大家指點迷津吧..

--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.115.47.165
※ 文章網址: http://www.ptt.cc/bbs/C_and_CPP/M.1410531700.A.6AF.html
Feis: 看起來是有機會被最佳化掉 09/13 03:05
Feis: 我想這算是要求編譯器給個保證.. 09/13 03:15
Feis: 但是中間那段話我也有點不知其所以 09/13 03:21
Feis: 感覺 C11 的那個實作除了比較慢沒有太大問題 09/13 03:23
windows2k: 我的問題是如果可能被最佳化掉, 那為什麼大家都這麼做 09/13 07:29
windows2k: 還是大家約定俗成完全無視? 09/13 07:29
lsc36: 話說這篇有part2 結論有點恐怖... 09/14 01:19
carylorrk: 總覺得太鑽牛角尖了 真的是非常非常罕見的例子吧XD? 09/14 04:29
windows2k: 沒辦法, 自從heartbleed之後,大家對資安特別敏感 09/14 09:00
windows2k: 哪邊該清沒清總是要特別關心,不然不重要誰理他 09/14 09:01

> -------------------------------------------------------------------------- <

作者: Feis (永遠睡不著 @@) 看板: C_and_CPP
標題: Re: [問題] volatile的正確用法
時間: Sat Sep 13 20:34:03 2014

※ 引述《windows2k (程式宅 <囧>)》之銘言:
windows2k: 我的問題是如果可能被最佳化掉, 那為什麼大家都這麼做 09/13 07:29
windows2k: 還是大家約定俗成完全無視? 09/13 07:29

我的看法是:

1. 會被最佳化的情況很少見. 一般情況下, 你不會產生不能被最佳化的情況.
像網頁提的那種例子, 正常意識到自己在幹嘛的人都會用 volatile 宣告變數
如果變數本身是 volatile, 當然用 memset 有它的風險. 知道風險還去做. 那怪不得別人.

2. 真的要做的話, 寫 memset 的 volatile 版本我相信在一般的編譯器不會有甚麼問題.
像網頁說的那個問題還是著重在對標準的 volatile 行為該怎麼解釋.
我相信宣告變數本身為 volatile 又使用 memset 的 volatile 版本時, 應該不會有甚麼其他問題. (自以為)

3. 如果你真的真的很 care, 那就使用 memset_s 吧, 至少編譯器要保證它是可以用的 XD


> -------------------------------------------------------------------------- <

作者: Killercat (殺人貓™) 看板: C_and_CPP
標題: Re: [問題] volatile的正確用法
時間: Sat Sep 13 20:53:23 2014

我自己看過volatile會用在這幾個地方,可以參考一下

1. 大多數的Device都會在kernel space map一塊記憶體作為溝通之用
這塊100%是volatile,不然穩死

簡單說這塊記憶體內容根本不是自己控制的,所以每次查詢都需要去peek

2. 這情況雖然我不覺得需要volatile,但是很多人認為是需要的
就是threading的global部分(這是個多危險的東西啊 XD)

我總覺得這用法是從java來的,java會用volatile做某種程度的synchronized
我不知道C有沒有這種行為

3. shmat拿到的void*取值後最好要volatile,別鐵齒,雖然看起來是user space


> -------------------------------------------------------------------------- <

作者: CindyLinz (Cindy Wang) 看板: C_and_CPP
標題: Re: [問題] volatile的正確用法
時間: Sun Sep 14 14:43:00 2014

※ 引述《windows2k (程式宅 <囧>)》之銘言:
: 不過中間有句話不太明瞭
: The C standard states that accesses to volatile objects are part of the
: unalterable observable behaviour — but it says nothing about accesses via
: lvalue expressions with volatile types. Consequently a sufficiently
: intelligent compiler can still optimize the buffer-zeroing away in this case
: — it just has to prove that the object being accessed was not originally
: defined as being volatile.
我講一下我對這段話套用在這個 memset 例子的字面理解..

這個 memset 裡面把指標宣告為指向 volatile 的指標,
用這個指標來存取東西的時候是這一段文字裡面說的
「via lvalue expression with volatile types
強調它是 volatile types 是因為我們是從這個指標來判斷的,
而不是這一塊被指的記憶體本身來看的.
這個 volatile 指標可能指向 volatile 記憶體, 也可能指向 non-volatile 記憶體,
這段話最前面說的
「access to volatile objects」
指的是一塊記憶體本身被標為 volatile.

所以, 他說這個 memset 有效, 是因為 compiler 還不夠聰明,
還沒辦法直接看出背後指到的記憶體是什麼, 所以就先用指標的型態判斷了,
但萬一有一天 compiler 覺醒了, 發現你只是用指標在騙他,
他看穿你的把戲以後可能就會怒把它 optimize 掉.. XD

--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 112.121.80.249
※ 文章網址: http://www.ptt.cc/bbs/C_and_CPP/M.1410676983.A.3B6.html
※ 編輯: CindyLinz (112.121.80.249), 09/14/2014 14:45:03
purincess: 拜大神(_m_) 09/14 23:00

> -------------------------------------------------------------------------- <

作者: csee (CSE) 看板: C_and_CPP
標題: Re: [問題] volatile的正確用法
時間: Wed Sep 17 16:29:00 2014

貢獻一下我自己對volatile的看法:
一開始我自己也是一知半解, 後來接觸嵌入式領域以後才比較清楚.

關於volatile的解釋是:
如果一個變數會因為外力而改變(非程式控制流程)
那每次取值請到memory中去讀取

一般而言, compiler會把 一個變數會被放在CPU的register or cache,
因為DRAM 的latency可是很嚇人的
( DRAM 光 RTL 讀取都要好幾個cycle, 更遑論CPU處理 )
所以直接放在CPU中or Cache中可以快速取值.

然而某些情況 如果某些變數的值會被ISR改變,
這種情況, 到快取中取得的值就是錯誤的
因此你必須每次都到記憶體中去抓取.

例如Timer_ticks就是個很好的例子.
因為timer的值並非是自己寫的程式主動去改動,
因此需要宣告成volatile, 告訴CPU抓取這個值的時候必須到記憶體中去讀取.


※ 引述《windows2k (程式宅 <囧>)》之銘言:
: 開發平台(Platform): (Ex: VC++, GCC, Linux, ...)
: VC++/GCC/CLANG
: 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
: None
: 問題(Question):
: volatile大概是C/C++最難了解的關鍵字之一
: 最近在看完這篇[How to zero a buffer](http://bit.ly/1wmpbys)產生的問題
: 在開啟最佳化之後,對照Assembly Code,所有的編譯器會捨棄掉stack上的memset。
: 不過如果照他的方式刻一個,會發現所有Compiler都會做清空的動作
: static void
: secure_memzero(void * p, size_t len)
: {
: volatile uint8_t * _p = p;
: while (len--) *_p++ = 0;
: }
: 不過中間有句話不太明瞭
: The C standard states that accesses to volatile objects are part of the
: unalterable observable behaviour — but it says nothing about accesses via
: lvalue expressions with volatile types. Consequently a sufficiently
: intelligent compiler can still optimize the buffer-zeroing away in this case
: — it just has to prove that the object being accessed was not originally
: defined as being volatile.
: 我不知道這段話是否正確,不過還沒找到Standard是否有類似的規定
: 如果這段話是正確的話,目前找到的
: C11的[memset_s](http://bit.ly/1qJG7vv)
: Windows的[SecureZeroMemory](http://bit.ly/1oC33rV)
: 作法都一樣,難道不怕被最佳化掉嘛
: 請大家指點迷津吧..


> -------------------------------------------------------------------------- <

作者: JLong (白開水的味道) 看板: C_and_CPP
標題: Re: [問題] volatile的正確用法
時間: Sat Oct 4 08:21:11 2014

※ 引述《windows2k (程式宅 <囧>)》之銘言:
: 開發平台(Platform): (Ex: VC++, GCC, Linux, ...)
: VC++/GCC/CLANG
: 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
: None
: 問題(Question):
: volatile大概是C/C++最難了解的關鍵字之一
: 最近在看完這篇[How to zero a buffer](http://bit.ly/1wmpbys)產生的問題
: 在開啟最佳化之後,對照Assembly Code,所有的編譯器會捨棄掉stack上的memset。
: 不過如果照他的方式刻一個,會發現所有Compiler都會做清空的動作
: static void
: secure_memzero(void * p, size_t len)
: {
: volatile uint8_t * _p = p;
: while (len--) *_p++ = 0;
: }
: 不過中間有句話不太明瞭
: The C standard states that accesses to volatile objects are part of the
: unalterable observable behaviour — but it says nothing about accesses via
: lvalue expressions with volatile types. Consequently a sufficiently
: intelligent compiler can still optimize the buffer-zeroing away in this case
: — it just has to prove that the object being accessed was not originally
: defined as being volatile.
針對這段敘述, 我分享自己的理解給你參考. (抱歉, 好像有點時間了~~)

In particular, the C standard states that the observable behaviour includes
accesses to volatile objects.

首先, 第一句話與文章最一開始提到 volatile 的地方要表達的意思一樣
(In particular, the C standard states that the observable behaviour includes
accesses to volatile objects), access volatile objects 是一個'會被看見'的行為,
compiler 不會對此做 optimize. 但以 lvalue expressions with volatile type 去
access object (即這段文字的上面的例子), C standard 沒有提到這種 case 的
behavior. 最後, 一個夠聰明的 compiler 只要證明所 access 的 object 不是原先就
被定義為 volatile, 它依然可以做 optimization (所以 secure_memzero() 同樣可能被
optimize).

這篇文章要探討的是如何避免 compiler 在特定狀況時, 因為 optimization 而衍生出的
安全性問題. 其中利用 volatile 的特性是一個可能的方式, 而且在幾個 compiler 上的
確有用 (This does trick a few more compilers).

至於為什麼 compiler 會有這樣的行為, 第一段 code 下面有解釋, 最後一句話:
While this completely subverts our intention, it is perfectly legal: The
observable behaviour of the program is unchanged by the optimization.


你可能也想看看

搜尋相關網站