c++ - 在main()之前,C / C ++程序有什麼方法可以崩潰嗎?




9 Answers

使用gcc,您可以使用構造函數屬性標記函數(這會導致函數在main之前運行)。 在以下函數中, premain將在main之前調用:

#include <stdio.h>

void premain() __attribute__ ((constructor));

void premain()
{
    fputs("premain\n", stdout);
}

int main()
{
    fputs("main\n", stdout);
    return 0;
}

所以,如果premain存在崩潰的bug,你將在main之前崩潰。

程序在main()之前有什麼方法可以崩潰嗎?




如果你有一個C ++程序,它可以在輸入main之前通過函數和構造函數初始化變量和對象。 任何這些中的錯誤都可能導致程序崩潰。




簡單的答案是: 是的

更具體地說,我們可以區分這兩個原因。 我將它們稱為依賴於 實現且與實現無關的

根本不依賴於您的環境的一種情況是C ++中的靜態對象,這裡提到過。 以下代碼在main()之前死掉:

#include <iostream>

class Useless {
public:
    Useless() { throw "You can't construct me!"; }

};

static Useless object;

int main() {
    std::cout << "This will never be printed" << std::endl;

    return 0;
}

更有趣的是與平台相關的原因 。 這裡提到了一些。 這裡提到的一個是動態鏈接庫的使用(Windows中的DLL,Linux中的SO等) - 如果你的操作系統的加載器在main()之前加載它們,它們可能會導致你的應用程序在main()之前死掉main()

這個原因的更一般的版本是在調用入口點( main() )之前討論二進製文件的入口點所做的所有事情。 通常在構建二進製文件時,會有一個相當嚴重的代碼塊,當操作系統的加載器開始運行二進製文件時會調用這些代碼塊,當它完成時會調用main() 。 這段代碼的一個常見問題是初始化C / C ++標準庫。 此代碼可能由於多種原因而失敗(它嘗試為一個系統資源分配的任何類型的系統資源不足)。

在windows上的main()之前,二進製文件執行代碼的一個有趣的方法是使用TLS回調(谷歌會告訴你更多關於它們的信息)。 這種技術通常在惡意軟件中被發現,作為一種基本的反調試技巧(這個技巧當時用來欺騙ollydbg,不知道它是否仍然存在)。

關鍵是你的問題實際上等同於“有沒有辦法加載二進製文件會導致用戶代碼在main()的代碼之前執行?”,答案是地獄,是的!




我不確定,但如果你有這樣的全局變量:

static SomeClass object;

int main(){
   return 0;
}

'SomeClass'構造函數可能會在main執行之前使程序崩潰。




有很多種可能性。

首先,我們需要了解在main執行之前實際發生了什麼:

  • 加載動態庫
  • 全局變量的初始化
  • 一些編譯器,一些函數可以顯式執行

現在,任何這種情況都可能在幾個方面導致崩潰:

  • 通常的未定義行為(取消引用空指針,訪問內存,你不應該...)
  • 拋出的異常>因為沒有catch ,所以調用terminate並且程序結束

這當然很煩人,可能很難調試,這就是為什麼你應該盡可能地避免在main之前執行代碼,如果可以,或者在main顯式初始化,則更喜歡延遲初始化。

當然,當它是一個DLL失敗並且你無法修改它時,你就陷入了痛苦的世界。




這取決於你在“在main之前”的意思,但如果你的意思是“在你的main中的任何代碼實際執行之前”,那麼我可以想到一個例子:如果你在main中聲明一個大數組作為局部變量,並且這個數組的大小超過了可用的堆棧空間,那麼在第一行代碼執行之前,你可能會在進入main時獲得




class Crash
{
public:
  Crash( int* p )
  { *p = 0; }
};

static Crash static_crash( 0 );

void main()
{
}



你還沒有說過哪個平台/ libc。 在嵌入式世界中,經常有很多東西在main()之前運行 - 主要與平台設置有關 - 這可能會出錯。 (或者,如果你在常規操作系統上使用時髦的鏈接器腳本,所有的賭注都會關閉,但我想這很少見。)




我遇到過同樣的問題。 發現的根本原因是..在主進程中初始化了太多局部變量(巨大數組),導致局部變量大小超過1.5 mb。
這導致一個大的跳躍,因為堆棧指針非常大,並且操作系統將此跳轉檢測為無效並使程序崩潰,因為它可能是惡意的。

調試這個。
1.啟動GDB
2.在main處添加斷點
3.拆卸主體
4.檢查子$ 0xGGGGGGG,%esp
如果此GGGGGG值過高,您將看到與我相同的問題。

因此,檢查main中所有局部變量的總大小。




Related