Действительно ли там каким-либо путем является программа C/C++, может отказать прежде основной ()?

Действительно ли там каким-либо путем является программа, может отказать прежде основной ()?

63
задан Matthieu M. 26 March 2010 в 09:57
поделиться

16 ответов

обязательно на C ++; статические объекты с конструкторами будут вызываться перед main - они могут умереть

не уверен насчет c

вот пример

class X
{
public:
X()
{
  char *x = 0;
  *x = 1;
}
};

X x;
int main()
{
return 0;
}

это выйдет из строя раньше main

18
ответ дан 24 November 2019 в 16:10
поделиться

Я не уверен, но если у вас есть такая глобальная переменная, как эта:

static SomeClass object;

int main(){
   return 0;
}

Конструктор SomeClass мог вызвать сбой программы перед основным выполняется.

6
ответ дан 24 November 2019 в 16:10
поделиться

Вы не сказали, какая платформа / libc. Во встраиваемом мире часто есть много вещей, которые выполняются перед main () - в основном это связано с настройкой платформы - что может пойти не так. (Или, действительно, если вы используете забавный скрипт компоновщика в обычной ОС, все ставки отключены, но я думаю, что это довольно редко.)

1
ответ дан 24 November 2019 в 16:10
поделиться

Есть много возможностей.

Во-первых, нам нужно понять, что на самом деле происходит перед выполнением main:

  • Загрузка динамических библиотек
  • Инициализация глобальных объектов
  • Некоторые компиляторы, некоторые функции могут выполняться явно

Теперь любой из-за этого может произойти сбой несколькими способами:

  • обычное неопределенное поведение (разыменование нулевого указателя, доступ к памяти не должен ...)
  • исключение, выброшенное>, поскольку нет ловушки , Вызывается terminate и конец программы

Конечно, это действительно раздражает и, возможно, трудно отлаживать, поэтому вам следует по возможности воздерживаться от выполнения кода перед main , и предпочитайте ленивую инициализацию, если это возможно, или явную инициализацию в main .

Конечно, когда DLL дает сбой, и вы не можете ее изменить, вас ждет целый мир боли.

5
ответ дан 24 November 2019 в 16:10
поделиться

Это зависит от того, что вы имеете в виду под словом «до main», но если вы имеете в виду «до того, как какой-либо из ваших кодов в main действительно будет выполнен», то я могу вспомнить один пример: если вы объявите большой массив как локальную переменную в main , и размер этого массива превышает доступное пространство стека, тогда вы вполне можете получить переполнение стека при входе в main, прежде чем будет выполнена первая строка кода.

3
ответ дан 24 November 2019 в 16:10
поделиться

Если у вас есть программа на C ++, она может инициализировать переменные и объекты с помощью функций и конструкторов до того, как будет введено main. Ошибка в любом из них может привести к сбою программы.

20
ответ дан 24 November 2019 в 16:10
поделиться
class Crash
{
public:
  Crash( int* p )
  { *p = 0; }
};

static Crash static_crash( 0 );

void main()
{
}
2
ответ дан 24 November 2019 в 16:10
поделиться

Несколько надуманный Например:

int a = 1;
int b = 0;
int c = a / b;

int main()
{
    return 0;
}

Маловероятно, что вы когда-нибудь сделаете что-то подобное, но если вы много занимаетесь макромагией, это вполне возможно.

2
ответ дан 24 November 2019 в 16:10
поделиться

Любая программа, которая полагается на общие объекты (DLL), загружаемые до того, как основная программа может выйти из строя раньше, чем основная.

Под Linux код в библиотеке динамического компоновщика (ld - *. So) запускается для предоставления любых библиотечных зависимостей задолго до main. Если какие-либо необходимые библиотеки не могут быть найдены, имеют разрешения, которые не позволяют вам получить к ним доступ, не являются обычными файлами или не имеют какого-либо символа, который динамический компоновщик, связавший вашу программу, думал, что он должен иметь, когда он связал вашу программу, тогда это может вызвать сбой.

Кроме того, каждая библиотека может запускать некоторый код, когда она связана. В основном это связано с тем, что библиотеке может потребоваться связать больше библиотек или может потребоваться запустить некоторые конструкторы (даже в программе на C в библиотеках может быть какой-то C ++ или что-то еще, в котором используются конструкторы). Кроме того, стандартный C программы уже создали ФАЙЛЫ stdio stdin, stdout и stderr. Во многих системах они также могут быть закрыты. Это означает, что они также свободны () ed, что означает, что они (и их буферы) были malloc () ed, что может дать сбой. Это также предполагает, что они, возможно, сделали какие-то другие действия с файловыми дескрипторами, которые представляют эти структуры FILE, что могло привести к сбою.

Другие вещи, которые могли бы произойти, могли произойти, если бы ОС испортила настройку переменных окружения и / или аргументов командной строки, которые были переданы программе. Код перед main, вероятно, должен был что-то сделать с этими данными перед вызовом main.

Многое происходит до main. Любой из них может потерпеть фатальный отказ.

10
ответ дан 24 November 2019 в 16:10
поделиться

Да хотя бы под Windows. Если программа использует библиотеки DLL, их можно загрузить до запуска main () . Функции DllMain этих DLL будут выполняться до main () . Если они столкнутся с ошибкой, они могут вызвать остановку всего процесса или сбой.

33
ответ дан 24 November 2019 в 16:10
поделиться

Типа: http://blog.ksplice.com/ 2010/03 / libc-free-world /

Если вы компилируете без стандартной библиотеки, например: gcc -nostdlib -o hello hello.c

, он не будет знать, как запустить main ( ) и рухнет.

4
ответ дан 24 November 2019 в 16:10
поделиться

Глобальные и статические объекты в программе на C++ будут иметь свои конструкторы, вызываемые до выполнения первого оператора в main(), поэтому ошибка в одном из конструкторов может привести к краху.

В программах на Си такого не происходит.

3
ответ дан 24 November 2019 в 16:10
поделиться

В gcc вы можете пометить функцию атрибутом constructor (который заставляет функцию запускаться перед 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 будет ошибка, вы потерпите крах до main.

36
ответ дан 24 November 2019 в 16:10
поделиться

некоторые библиотеки абстракции платформы переопределяют (я лично знаю только библиотеки C++, такие как Qt или ACE, которые делают это, но возможно некоторые библиотеки C тоже делают что-то подобное) "main", так что они указывают специфический для платформы main, как int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) и настроить некоторые библиотечные вещи, преобразовать args командной строки в нормальные int argc, char* argv[] и затем вызвать нормальную int main(int argc, char* argv[])

Конечно, такие библиотеки могут привести к краху, если они не реализовали это правильно (возможно, из-за неправильно сформированных args командной строки).

И для людей, которые не знают об этом, это может выглядеть как крах перед main

1
ответ дан 24 November 2019 в 16:10
поделиться

Конечно, если есть ошибка в операционной системе или во время выполнения. C ++ особенно известен таким поведением, но это все еще может происходить в C.

1
ответ дан 24 November 2019 в 16:10
поделиться

Простой ответ: Да .

Более конкретно, мы можем различать две причины этого. Я назову их зависимыми от реализации и независимыми от реализации .

Единственный случай, который совсем не зависит от вашей среды , - это случай статических объектов в 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;
}

Более интересны платформо-зависимые причины . Некоторые из них были упомянуты здесь. Пару раз здесь упоминалось об использовании динамически подключаемых библиотек (DLL в Windows, SO в Linux и т. Д.) - если загрузчик вашей ОС загружает их до main () , они могут вызвать у вас приложение умирает раньше main () .

Более общая версия этой причины говорит обо всем, что делает точка входа вашего двоичного файла перед вызовом вашей точки входа ( main () ).Обычно, когда вы создаете свой двоичный файл, существует довольно серьезный блок кода, который вызывается, когда загрузчик вашей операционной системы запускает ваш двоичный файл, и когда он завершается, он вызывает вашу main () . Обычно этот код выполняет инициализацию стандартной библиотеки C / C ++. Этот код может выйти из строя по любому количеству причин (нехватка любого системного ресурса, который он пытается выделить для одной).

Одним из интересных способов выполнения кода перед main () в Windows является использование обратных вызовов TLS (Google расскажет вам о них больше). Этот метод обычно используется во вредоносных программах как базовый трюк для защиты от отладки (тогда этот прием использовался для обмана ollydbg, не знаю, работает ли он до сих пор).

Дело в том, что ваш вопрос на самом деле эквивалентен «есть ли способ, при котором загрузка двоичного файла вызвала бы выполнение кода пользователя перед кодом в main () ?», И ответ будет ] черт возьми!

18
ответ дан 24 November 2019 в 16:10
поделиться