Как устранить ошибку Segmentation fault; core dumped при работе с указателями C ? — Хабр Q&A

Вводная

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;
    }
}

возникает ошибка:

:/>  Проводник файлов Windows 10 - База полезных знаний

Segmentation fault; core dumped;

Такая же возникает ошибка, если в классе Calculator сделать что-то вроде :

string str = this->ui->calc->leftOperand; // Segmentation fault; core dumped

При дебаге в переменных видны “странные” для меня значения, ведь ожидаются простые строки:
5b3874af7b5f8755241208.png

Почему возникает эта ошибка и как ее исправить?

Не запускается сервер

§

Ошибка 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.
:/>  Эмулятор айфона на пк windows 10 на русском

Минусов оказалось настолько много, что приходится искать второе решение.

Способ 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-совместимой ОС.

Оставьте комментарий

Adblock
detector