Вводная
C является «небезопасным» («unmanaged») языком, поэтому программы могут «вылетать» — аварийно завершать работу без сохранения данных пользователя, сообщения об ошибке и т.п. — стоит только, например, залезть в не инициализированную память. Например:
void fall()
{ char * s = "short_text"; sprintf(s,"This is very long text");
}
или
void fall()
{ int * pointer = NULL; *pointer = 13;
}
Всем было бы лучше, если бы мы могли «отловить» падение программы — точно так же, как в java ловим исключения — и выполнить хоть что-то перед тем, как программа упадет (сохранить документ пользователя, вывести диалог с сообщением об ошибке и т.п.)
Общего решения задача не имеет, так как C не имеет собственной модели обработки исключений, связанных с работой с памятью. Тем не менее, мы рассмотрим два способа, использующих особенности операционной системы, вызвавшей исключение.
Как устранить ошибку segmentation fault; core dumped при работе с указателями c ?
Есть 2 класса:
1) UI
//UI.h
#ifndef UI_H
#define UI_H
#include <map>
#include <string>
#include <FL/Fl_Button.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Widget.H>
using namespace std;
class App;
class Calculator;
class UI {
public: Fl_Window *flWindow; map< string, Fl_Box* > flBox; map< string, Fl_Button*> flButtons; Fl_Output *output; App *app; Calculator *calc; UI(App* app); void startWindow(); void endWindow(); void createUI(); static void resetOutputCb(Fl_Widget *w, void *data); void changeOutputValue(); void prepareOutput(string& insertedValue, bool isNewAction);
};
#endif /* UI_H */
2) Calculator:
//Calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include <string>
#include <FL/Fl_Widget.H>
using namespace std;
class UI;
class Calculator {
public: Calculator(UI *ui); UI *ui; string leftOperand; string action; string rightOperand; static void clickButtonCb(Fl_Widget *w, void *data); bool isNewAction(string action);
private: void makeCalc(bool isNewValue); double plus(double x, double y);
};
#endif /* CALCULATOR_H */
Класс UI инициализирует класс Calсulator и передает ему указатель на самого себя:
UI::UI(App *app) { this->app = app; this->calc = new Calculator(this);
}
Класс Calculator в свою очередь записывает указатель на UI в одно из своих свойств:
Calculator::Calculator(UI *ui) :
leftOperand("0"),
rightOperand(""),
action("") { this->ui = ui;
}
}
Однако теперь при попытке вызвать из Calculator метод класса UI:
void UI::prepareOutput(string& insertedValue, bool isNewAction) { if (calc->action != "" && !isNewAction) { // странно, что при calc->action != "" ошибки нет if (calc->rightOperand == "0") { calc->rightOperand = ""; } calc->rightOperand = insertedValue; // НО ВОТ ТУТ Возникает ошибка при работе с calc->rightOperand } else if (!isNewAction) { if (calc->leftOperand == "0") { calc->leftOperand = ""; } calc->leftOperand = insertedValue; } if (isNewAction && calc->rightOperand == "" && calc->action != "" && insertedValue != "=") { calc->action = insertedValue; }
}
возникает ошибка:
Segmentation fault; core dumped;
Такая же возникает ошибка, если в классе Calculator сделать что-то вроде :
string str = this->ui->calc->leftOperand; // Segmentation fault; core dumped
При дебаге в переменных видны “странные” для меня значения, ведь ожидаются простые строки:
Почему возникает эта ошибка и как ее исправить?
Не запускается сервер
§
Ошибка segmentation fault (core dumped)
Есть данный код на СИ, суть в том, чтобы в двумерном массиве с помощью потоков (Linux) найти самую большую последовательность чисел по возрастанию. При компиляции всё хорошо, а как запускаю программу появляется ошибка Segmentation fault (core dumped)
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
void random1(int arr[5][100]) {
int i,j;
for(i=0; i<5;i )
{
for(j=0; j<100;j )
{
arr[i][j]=rand()0;
printf("%dt", arr[i][j]);
}
printf("n");
}
printf("n");
}
void* thread_func1(int arr[5][100]){
int buffer = 1, maxbuffer=0, max=0, minElement=0, maxElement;
int i,j;
for(i=0;i<5;i )
{
for(j=0;j<100;j )
{
if(arr[i][j 1]>arr[i][j])
{
buffer ;
max=buffer;
if(maxbuffer<max)
{
maxbuffer = max;
maxElement = arr[i][j 1];
}
}
if(arr[i][j 1]<=arr[i][j])
{
max=buffer;
if(maxbuffer<max)
{ maxbuffer = max;
maxElement = arr[i][j 1];
}
buffer = 1;
}
}
minElement = (maxElement 1)-maxbuffer;
for( i = minElement; i<=maxElement; i )
{
printf("%dt", arr[i][j]);
}
}
}
int main() {
int A[5][100];
int stime;
stime=time(NULL);
srand(stime);
random1(A);
pthread_t k1,k2;
pthread_create(&k1, NULL, (void*)thread_func1,(int*)A);
pthread_join(k1,NULL);
printf("%ld",k1);
exit (0);
}
Еще один пример реализации функции thread_func1, но там тоже выходит эта ошибка
void* thread_func1(int arr[5][100]){
int start=0, lenght=1, max_start=0, max_lenght=0;
int i,j;
for(i=0;i<5;i ){
for(j=0;j<100;j ){
for(int k=j 1;k<100;k )
{
if(arr[i][j]<arr[i][k])
lenght ;
else{
if(lenght>max_lenght)
max_lenght= lenght, max_start=start;
start = k, lenght = 1;
}
}
}
}
for(i = max_start; i<max_start max_lenght; i ){
for (j=max_start; i<max_start max_lenght; i ){
printf("%p", arr[i][j]);}}}
Ошибка:segmentation fault (core dumped): как можно исправить (shared memory) c
Ошибка слишком проста – Вы пытаетесь обращаться к объекту, который не создали
std::queue<std::string>* str = (std::queue<std::string>*)shmat(ShmID, 0, 0);
то есть, str указывает на память, но что там… а кто его знает. Если обычную структуру так можно размещать, то с классы нужно только через конструктор.
// получим указатель на память
void *p = shmat(ShmID, 0, 0);
// используем placement new для создания объекта по месту
std::queue<std::string> * str = new(p)std::queue<std::string>();
после такого изменения уже не падает. Но нужно не забыть вызвать деструктор (delete str;
). И видимо его нужно вызвать только в одном из процессов. И самое главное – не вызвать его тогда, когда ещё другой процесс использует его.
Также нужно аккуратно посинхронизировать обращения к памяти, а то может быть очень весело – std::queue не ожидает, что он работает с разных процессов.
Способ 1: seh
Если Вы используете OS Windows в качестве целевой ОС и Visual C в качестве компилятора, то Вы можете использовать
— расширение языка С от Microsoft, позволяющее отлавливать любые исключения, происходящие в программе.
Общий синтаксис обработки исключений выглядит следующим образом:
__try
{ segfault1();
}
__except( condition1 )
{ // обработка исключения, если condition1 == EXCEPTION_EXECUTE_HANDLER. // в condition1 может (должен) быть вызов метода, проверяющего // тип исключения, и возвращающего EXCEPTION_EXECUTE_HANDLER // если тип исключения соответствует тому, что мы хотим обработать
}
__except( condition2 )
{ // еще один обработчик
}
__finally
{ // то, что выполнится если ни один из обработчиков не почешется
}
Вот «работающий пример» — «скопируй и вставь в Visual Studio»
#include <stdio.h>
#include <windows.h>
#include <excpt.h>
int memento() // обработка Segfault
{ MessageBoxA(NULL,"Memento Mori","Exception catched!",NULL); return 0;
}
void fall() // генерация segfault
{ int* p = 0x00000000; *p = 13;
}
int main(int argc, char *argv[])
{ __try { fall(); } __except (EXCEPTION_EXECUTE_HANDLER) { memento(); }
}
Мне лично не удалось заставить заработать __finally (поэтому я и написал __except с кодом проверки, который всегда работает), но это, возможно, кривизна моих рук.
Данная методика, при всей ее привлекательности, имеет ряд минусов:
- Один компилятор. Одна ОС. Не «чистый С ». Если Вы хотите работать без средств MS — Вы не сможете использовать эту методику
- Один поток — одна таблица. Если Вы напишете конструкцию из __try… __except, внутри __try запустите другой поток и, не выходя из __try второй поток вызовет segfault, то… ничего не произойдет, программа упадет «как обычно». Потому, что на каждый поток нужно писать отдельный обработчик SEH.
Минусов оказалось настолько много, что приходится искать второе решение.
Способ 2: posix — сигналы
Способ рассчитан на то, что в момент падения программа получает POSIX-сообщение SIGSEGV. Это безусловно так во всех UNIX-системах, но это фактически так (хотя никто не гарантировал, windows — не posix-совместима) и в windows тоже.
Методика простая — мы должны написать обработчик сообщения SIGSEGV, в котором программа совершит «прощальные действия» и, наконец, упадет:
void posix_death_signal(int signum)
{ memento(); // прощальные действия signal(signum, SIG_DFL); // перепосылка сигнала exit(3); //выход из программы. Если не сделать этого, то обработчик будет вызываться бесконечно.
}
после чего мы должны зарегистрировать этот обработчик:
signal(SIGSEGV, posix_death_signal);
Вот готовый пример:
#include <stdio.h>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <signal.h>
int memento()
{ int a=0; MessageBoxA(NULL,"Memento mori","POSIX Signal",NULL); return 0;
}
void fall()
{ int* p = 0x00000000; *p = 13;
}
void posix_death_signal(int signum)
{ memento(); signal(signum, SIG_DFL); exit(3);
}
int main(int argc, char *argv[])
{ signal(SIGSEGV, posix_death_signal); fall();
}
В отличие от SEH, это работает всегда: решение «многопоточное» (вы можете уронить программу в любом потоке, обработчик запустится в любом случае) и «кроссплатформенное» — работает под любым компилятором, и под любой POSIX-совместимой ОС.