Есть ли способ, с которым программа может потерпеть крах перед main()?
Есть ли способ, с помощью которого программа C/С++ может сбой перед main()?
Ответ 1
С помощью 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
имеется ошибка при сбое, вы потерпите крах перед main
.
Ответ 2
Да, по крайней мере, под Windows. Если программа использует библиотеки DLL, их можно загрузить до начала main()
. Функции DllMain
этих DLL будут выполняться до main()
. Если они столкнутся с ошибкой, они могут привести к остановке или сбою всего процесса.
Ответ 3
Если у вас есть программа на C++, она может инициализировать переменные и объекты через функции и конструкторы до ввода основной. Ошибка в любом из них может привести к сбою программы.
Ответ 4
обязательно в С++; статические объекты с конструкторами будут вызваны до main - они могут умереть
не уверен о c
здесь находится образец
class X
{
public:
X()
{
char *x = 0;
*x = 1;
}
};
X x;
int main()
{
return 0;
}
это приведет к сбою перед основным
Ответ 5
Простой ответ: Да.
В частности, мы можем различать две причины этого. Я буду называть их зависимыми от реализации и независимыми от реализации.
Один случай, который не зависит от вашей среды вообще, относится к статическим объектам в С++, о чем упоминалось здесь. Следующий код умирает до 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()
.
Более общая версия этой причины говорит обо всех вещах вашей двоичной точки входа, прежде чем вызывать точку входа <<20 > ). Обычно, когда вы создаете свой двоичный код, есть довольно серьезный блок кода, который вызывается, когда загрузчик вашей операционной системы начинает запускать ваш двоичный файл, а когда он это делает, он вызывает ваш main()
. Одной из распространенных вещей, которые делает этот код, является инициализация стандартной библиотеки C/С++. Этот код может не работать по ряду причин (нехватка любого системного ресурса, который он пытается выделить для одного).
Один интересный способ для двоичного кода выполнить код до main()
в Windows - использовать обратные вызовы TLS (Google расскажет вам больше о них). Этот метод обычно обнаруживается в вредоносных программах как основной анти-отладочный трюк (этот трюк, используемый для обмана ollydbg в то время, не знает, продолжает ли он это делать).
Дело в том, что ваш вопрос на самом деле эквивалентен "есть ли способ, по которому загрузка двоичного кода приведет к выполнению кода пользователя перед кодом в main()
?", а ответ hell, yeah!
Ответ 6
Любая программа, которая полагается на общие объекты (DLL), загружаемые до того, как main может завершиться с ошибкой до основного.
В разделе кода Linux в библиотеке динамических компоновщиков (ld - *. so) выполняется для обеспечения любых зависимостей библиотеки задолго до основного. Если какие-либо необходимые библиотеки не могут быть расположены, имеют разрешения, которые не позволяют вам получить к ним доступ, не являются нормальными файлами или не имеют какого-либо символа, который динамический компоновщик, который связал вашу программу, считал, что он должен иметь, когда он связал вашу программу, тогда это может привести к сбою.
Кроме того, каждая библиотека получает код, когда он связан. Это связано главным образом с тем, что библиотеке может потребоваться связать больше библиотек или, возможно, потребуется запустить некоторые конструкторы (даже в программе на языке C, в библиотеках может быть некоторый С++ или что-то еще, использующее конструкторы). Кроме того, стандартные программы C уже создали stdio FILEs stdin, stdout и stderr. На многих системах они также могут быть закрыты. Это означает, что они также являются бесплатными() ed, что означает, что они (и их буферы) были malloc() ed, что может потерпеть неудачу. Это также предполагает, что они, возможно, сделали некоторые другие вещи для файловых дескрипторов, которые представляют эти структуры FILE, которые могут потерпеть неудачу.
Другие вещи, которые могли бы произойти, могли быть, если бы ОС пришлось испортить настройку переменных окружения и/или аргументов командной строки, которые были переданы программе. Код перед основным, вероятно, должен был что-то с этими данными перед вызовом main.
Множество вещей происходит до основного. Любой из них может со всей очевидностью потерпеть неудачу.
Ответ 7
Я не уверен, но если у вас есть глобальная переменная вроде этого:
static SomeClass object;
int main(){
return 0;
}
Конструктор "SomeClass" может привести к сбою программы до того, как будет выполнен основной файл.
Ответ 8
Существует много возможностей.
Во-первых, нам нужно понять, что на самом деле происходит до того, как выполняется main:
- Загрузка динамических библиотек
- Инициализация глобальных символов
- Один из некоторых компиляторов, некоторые функции могут выполняться явно
Теперь любое из этого может вызвать сбой несколькими способами:
- обычное поведение undefined (разыменование нулевого указателя, обращение к памяти вам не нужно...)
- исключение выбрано > , поскольку не существует
catch
,terminate
вызывается и конец программы
Это действительно раздражает, конечно, и, возможно, трудно отлаживать, и именно поэтому вы должны воздерживаться от выполнения кода до main
как можно больше и предпочитаете ленивую инициализацию, если можете, или явную инициализацию внутри main
.
Конечно, когда это происходит с ошибкой DLL, и вы не можете ее изменить, вы находитесь в мире боли.
Ответ 9
Вид: http://blog.ksplice.com/2010/03/libc-free-world/
Если вы компилируете без стандартной библиотеки, например: gcc -nostdlib -o hello hello.c
он не будет знать, как запустить main() и сработает.
Ответ 10
Глобальные и статические объекты в программе на С++ будут вызывать их конструкторы до того, как будет выполнен первый оператор в main(), поэтому ошибка в одном из конструкторов может вызвать сбой.
Это не может произойти в программах на C.
Ответ 11
Это зависит от того, что вы подразумеваете под "до основного", но если вы имеете в виду "прежде чем какой-либо из вашего кода в основном выполняется", тогда я могу вспомнить один пример: если вы объявляете большой массив как локальную переменную в main, и размер этого массива превышает доступное пространство стека, тогда вы можете получить запись stack overflow
на главной странице, прежде чем будет выполняться первая строка кода.
Ответ 12
Несколько надуманный пример:
int a = 1;
int b = 0;
int c = a / b;
int main()
{
return 0;
}
Невероятно, чтобы вы когда-либо делали что-то подобное, но если вы делаете много макромагии, это вполне возможно.
Ответ 13
class Crash
{
public:
Crash( int* p )
{ *p = 0; }
};
static Crash static_crash( 0 );
void main()
{
}
Ответ 14
Конечно, если есть ошибка в операционной системе или во время выполнения кода. С++ особенно известен этим поведением, но он все равно может произойти в C.
Ответ 15
Вы не сказали, какая платформа /libc. Во встроенном мире часто существует много вещей, которые выполняются до main()
- в основном, для настройки платформы, что может пойти не так. (Или, действительно, если вы используете фанки-компоновщик script на обычной ОС, все ставки отключены, но я думаю, что это довольно редко.)
Ответ 16
некоторые библиотеки абстракции платформы переопределяют (я лично знаю только библиотеки С++, такие как Qt или ACE, которые делают это, но, возможно, некоторые библиотеки C тоже делают что-то подобное) "main", так что они определяют основную платформу, например a int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow );
и настройте некоторые материалы библиотеки, преобразуйте аргументы командной строки в обычный int argc, char* argv[]
, а затем вызовите обычный int main(int argc, char* argv[])
Конечно, такие библиотеки могут привести к сбою, когда они не реализуют это правильно (возможно, причина неверных аргументов командной строки).
И для людей, которые не знают об этом, это может выглядеть как сбой перед main
Ответ 17
Я столкнулся с той же проблемой. Обнаружена основная причина. Слишком много локальных переменных (огромные массивы) были инициализированы в основном процессе, в результате чего размер локальных переменных превысил 1,5 мб.
Это приводит к большому прыжку, поскольку указатель стека довольно велик, и ОС обнаруживает этот скачок как недействительный и выдает сообщение о сбое программы, поскольку это может быть вредоносным.
Отладить это.
1. Запустите GDB
2. Добавить точку останова на главной странице
3. разобрать главный
4. Проверьте наличие sub $0xGGGGGGG,% esp
Если это значение GGGGGG слишком велико, вы увидите ту же проблему, что и я.
Итак, проверьте общий размер всех локальных переменных в главном.
Ответ 18
Лучший пример сбоя программы до main
при переполнении стека overflow:
int main() {
char volatile stackoverflow[1000000000] = {0};
return 0;
}