Try   HackMD

Linus 親自教你 C 語言 array argument 的使用

Linus Torvalds 在 2015 年 9 月份對著 David Miller 所提交的 Linux v4.3 merge window 上的變革,進行以下評語:

and others say that the most notable feature is the idiotic bugs that it introduces, and the compiler even complains about.

究竟是什麼的愚蠢錯誤,讓 Linus 氣成這樣呢?以下摘錄並解說:

This:

static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata,
                                  struct ieee80211_supported_band *sband,
                                  struct ieee80211_sta *sta, u32 *mask,
                                   u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])

is horribly broken to begin with, because array arguments in C don't actually exist. Sadly, compilers accept it for various bad historical reasons, and silently turn it into just a pointer argument. There are arguments for them, but they are from weak minds.

原來是傳遞一個 array argument,造成諾大的風波。

But happily gcc has a really really valid warning (kudos - I often end up ragging on the bad warnings gcc has, but this one is a keeper), because a few lines down the mistake then turns into pure and utter garbage.

而且編譯器明明有拋出警告訊息,接下來使用 array argument 來做運算的幾行程式碼才是 Linus 認定的垃圾。

It's garbage that was basically encouraged by the first mistake (thinking that C allows array arguments), namely:

for (i = 0; i < sizeof(mcs_mask); i++)

原因是對 array argument 進行 sizeof 操作 (注意: sizeof 是 operator),會得到的是指標型態物件佔用的空間。array argument 並非真正存在 C 語言,後者僅被視作一個指標。而且 Linus 抱怨說:用錯就算了,你還不知道計算 array size有 ARRAY_SIZE 巨集可用嗎?

在原始程式碼 include/linux/kernel.h 中,ARRAY_SIZE 實作如下:

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))

So I can see how this bug happened, and I am only slightly upset with Lorenzo who is the author of that commit.

Lorenzo,也就是該變更的提交人,我對你感到遺憾,怎麼會犯下這麼蠢的錯?

What I can't see is why the code has existed in at least two maintainer trees (Johannes' and David's) for a couple of weeks, and nobody cared about the new compiler warnings? And it was sent to me despite that new warning?

讓 Linus 感到不解的是,Johannes (Wireless 及 iwlwifi 子系統的維護人) 和 David (核心網路子系統的維護人) 兩位為何能讓糟糕的程式碼存在數週,就交付給 Linus 要求整合進入 Linux 核心?

I realy want people to take a really hard look at functions that use arrays as arguments. It really is very misleading, even if it can look "prettier", and some people will argue that it's "documentation" about how the pointer is a particular size. But it's neither. It's basically just lying about what is going on, and the only thing it documents is "I don't know how to C". Misleading documentation isn't documentation, it's a mistake.

也許有人想論述說,這是 C 語言指標的特例,但 Linus 要說,這樣的用法就只是記錄著 "I don't know how to C"

David Miller 表示說用 gcc 4.9.2 沒發現編譯器警告訊息,再來有人把所有的 array argument 都抓出來看,確認是否正確運用 sizeof 或 ARRAY_SIZE。Linus 也補充 array argument 的正確使用時機:

The "array as function argument" syntax is occasionally useful (particularly for the multi-dimensional array case), so I very much understand why it exists, I just think that in the kernel we'd be better off with the rule that it's against our coding practices.

參考資訊