簡體   English   中英

C標准是否定義了堆棧溢出行為?

[英]Does the C standard define a stack overflow behavior?

是否存在用於處理堆棧溢出的已定義行為?

除了終止這個過程之外,似乎還有很多事情可以完成。 我只是想知道是否有人可能知道C標准對此有何看法。

該標准不需要使用堆棧,並且沒有關於堆棧溢出的說法。

C99標准沒有定義堆棧; 它只討論摘要中的自動或分配存儲,而具有溢出檢測的連續堆棧只是實現自動存儲的一種機制。

該標准的第7.14節將SIGSEGV定義為“無效訪問存儲”時出現的信號。 C的實現不需要生成任何信號,但是如果檢測到堆棧溢出,則使用連續的固定大小堆棧*的實現通常用信號SIGSEGV。

您可以為SIGSEGV注冊信號處理函數,但它不能返回 - “[i] f並且當函數返回時,如果sig的值是SIGFPE,SIGILL,SIGSEGV或任何其他實現定義的值對應於a計算異常,行為[u] r未定義“

(*並不是說我已經故意使用C實現但沒有,但我不知道C標准中的任何內容阻止使用在其他環境中實現可擴展自動存儲域的常用技術)

C標准甚至沒有定義堆棧,所以它當然沒有定義堆棧溢出時會發生什么。

這里的答案是正確的,說它與c標准無關,但你的陳述“除了終止這個過程,似乎沒有一大部分可以完成”並不是 - 作為一般性 - 真正。

實際上,在大多數具有虛擬內存管理和按需分頁的系統上,分配的堆棧非常小(通常比當前使用的堆棧多4KB)並且經常溢出(這會產生頁面錯誤中斷)並且OS只會添加另一頁內存到線程的堆棧。

堆棧限制 - 通常為1MB,只是一個相當隨意的數字,用於防范失控程序,通常不是絕對限制(盡管它是在一些帶有intel處理器IIRC的內存型號上)。 通常,為每個線程分配1MB的物理內存是沒有意義的。

根據這個問題的一些答案,C標准甚至沒有任何關於堆棧存在的說法,更不用說堆棧溢出了。

我很確定操作系統定義了發生的具體細節,但是在所有情況下,程序都應該退出。 你是正確的,假設一旦發生堆棧溢出,你真的無能為力(至少作為程序員)。 你所能做的就是防止它們首先發生。

這取決於操作系統。 但是,許多操作系統允許覆蓋默認堆棧大小。 例如,在Windows上,您可以使用此鏈接器標志將堆棧大小從1MB增加到更高的值。

正如其他人提到的那樣,該標准沒有說明堆棧的任何內容。

但是,我認為它是定義堆棧溢出行為,標准會說它會導致未定義的行為。

::邊敲擊::

在某些系統上,在堆棧溢出后確保任何可預測的優惠都會給每個函數調用增加相當大的開銷; 因此,該標准非常合理地將堆棧溢出視為未定義行為。 如果目標是最大化實現可以運行合法程序的效率,那么這是完全合適的。

該標准也不要求系統具有足夠的堆棧來支持任何非平凡的函數調用深度。 鑒於一些有用的程序(特別是在嵌入式系統世界中)可以通過少於16個字節的堆棧來獲得,並且可能不一定能夠節省比這更多的RAM,需要大量堆棧會違反“不要”為你不需要的東西買單“。

遺憾的是,程序沒有辦法說出它需要什么樣的深度,也無法查詢可用的堆棧類型,唯一可以保證不參與未定義行為的程序就是那些堆棧使用情況低於最低保證金; 在嵌入式系統世界之外,這基本上意味着標准不保證任何比玩具更大的程序。

在這方面,C標准是矛盾的。 考慮以下程序:

void foo(uintptr_t n)
{
    int a;
    printf("%p\n", (void *)&a);
    if (n+1) foo(n+1);
}
int main()
{
    int a;
    printf("%p\n", (void *)&a);
    foo(0);
}

該程序完全符合並且不違反任何最小轉換限制,並且正如其他人所說的那樣,標准語言中沒有任何關於堆棧限制/溢出的內容。 但是,它產生UINTPTR_MAX + 2個對象a (在每個調用級別),它們的生命周期都重疊,每個對象都有不同的地址。 僅通過計數論證就不可能做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM