The core file is normally called core and is located in the current working directory of the process. However, there is a long list of reasons why a core file would not be generated, and it may be located somewhere else entirely, under a different name. See the core.5 man page for details:
DESCRIPTION
The default action of certain signals is to cause a process to
terminate and produce a core dump file, a disk file containing an
image of the process’s memory at the time of termination. This image
can be used in a debugger (e.g., gdb(1)) to inspect the state of the
program at the time that it terminated. A list of the signals which
cause a process to dump core can be found in signal(7).…
There are various circumstances in which a core dump file is not produced:
* The process does not have permission to write the core file. (By default, the core file is called core or core.pid, where pid is the ID of the process that dumped core, and is created in the current working directory. See below for details on naming.) Writing the core file will fail if the directory in which it is to be created is nonwritable, or if a file with the same name exists and is not writable or is not a regular file (e.g., it is a directory or a symbolic link). * A (writable, regular) file with the same name as would be used for the core dump already exists, but there is more than one hard link to that file. * The filesystem where the core dump file would be created is full; or has run out of inodes; or is mounted read-only; or the user has reached their quota for the filesystem. * The directory in which the core dump file is to be created does not exist. * The RLIMIT_CORE (core file size) or RLIMIT_FSIZE (file size) resource limits for the process are set to zero; see getrlimit(2) and the documentation of the shell's ulimit command (limit in csh(1)). * The binary being executed by the process does not have read permission enabled. * The process is executing a set-user-ID (set-group-ID) program that is owned by a user (group) other than the real user (group) ID of the process, or the process is executing a program that has file capabilities (see capabilities(7)). (However, see the description of the prctl(2) PR_SET_DUMPABLE operation, and the description of the /proc/sys/fs/suid_dumpable file in proc(5).) * (Since Linux 3.7) The kernel was configured without the CONFIG_COREDUMP option.In addition, a core dump may exclude part of the address space of the
process if the madvise(2) MADV_DONTDUMP flag was employed.Naming of core dump files
By default, a core dump file is named core, but the
/proc/sys/kernel/core_pattern file (since Linux 2.6 and 2.4.21) can
be set to define a template that is used to name core dump files.
The template can contain % specifiers which are substituted by the
following values when a core file is created:%% a single % character %c core file size soft resource limit of crashing process (since Linux 2.6.24) %d dump mode—same as value returned by prctl(2) PR_GET_DUMPABLE (since Linux 3.7) %e executable filename (without path prefix) %E pathname of executable, with slashes ('/') replaced by exclamation marks ('!') (since Linux 3.0). %g (numeric) real GID of dumped process %h hostname (same as nodename returned by uname(2)) %i TID of thread that triggered core dump, as seen in the PID namespace in which the thread resides (since Linux 3.18) %I TID of thread that triggered core dump, as seen in the initial PID namespace (since Linux 3.18) %p PID of dumped process, as seen in the PID namespace in which the process resides %P PID of dumped process, as seen in the initial PID namespace (since Linux 3.12) %s number of signal causing dump %t time of dump, expressed as seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC) %u (numeric) real UID of dumped process
|
Сергей2109 0 / 0 / 0 Регистрация: 23.01.2017 Сообщений: 3 |
||||
|
1 |
||||
|
23.01.2017, 20:30. Показов 51243. Ответов 7 Метки нет (Все метки)
Всем доброго времени суток. Не могли бы посмотреть кусок программы и подсказать ошибку. При компиляции ничего не выдаёт, а вот при запуске пишет Segmentation fault (core dumped). Спасибо всем.
__________________
0 |
|
Nemovok 296 / 125 / 106 Регистрация: 30.10.2015 Сообщений: 690 |
||||
|
23.01.2017, 20:38 |
2 |
|||
|
Эта ошибка означает, что вы вышли за границы массива.
Думаю меня поправят, если что
1 |
|
drfaust 544 / 379 / 123 Регистрация: 02.10.2008 Сообщений: 1,542 Записей в блоге: 1 |
||||||||
|
23.01.2017, 20:41 |
3 |
|||||||
|
Попробуйте i-j взять в скобки (не помню приоритеты):
Так же прога может вылетать в содержимом graph().
0 |
|
0 / 0 / 0 Регистрация: 23.01.2017 Сообщений: 3 |
|
|
23.01.2017, 20:44 [ТС] |
4 |
|
if (i-j>=0) out[i]+=koef[j]*in[i-j]; На этот случай есть условие, так что не знаю где там ещё может быть.
0 |
|
296 / 125 / 106 Регистрация: 30.10.2015 Сообщений: 690 |
|
|
23.01.2017, 20:50 |
5 |
|
if (i-j>=0) Не заметил
0 |
|
0 / 0 / 0 Регистрация: 23.01.2017 Сообщений: 3 |
|
|
23.01.2017, 20:51 [ТС] |
6 |
|
Тут вылетает именно в этой функции. Все проверил уже раз на сто). Не знаю почему, но если её запущу отдельно (как другая программа), то всё нормально. Вот и пытаюсь решить в чём проблема.
0 |
|
544 / 379 / 123 Регистрация: 02.10.2008 Сообщений: 1,542 Записей в блоге: 1 |
|
|
23.01.2017, 20:59 |
7 |
|
Тут вылетает именно в этой функции. C — язык весёлый. Если есть косяк (выход за пределы диапазона/выделенной памяти), то вылезти может где угодно. Я помниться в сотне килобайт исходников две недели ковырялся, в поисках бага — оказалось повторное освобождение памяти в очереди сообщений, а вылазило редко, не всегда и в самых неожиданных местах.
1 |
|
Вездепух
10420 / 5692 / 1550 Регистрация: 18.10.2014 Сообщений: 14,019 |
|
|
23.01.2017, 22:12 |
8 |
|
При компиляции ничего не выдаёт, а вот при запуске пишет Segmentation fault (core dumped). Где информация о том, в каком именно месте кода это происходит? Почему она не приведена в вашем первом сообщении? Существует миллион причин, по которым может произойти эта ошибка, и в вашем коде есть предпосылки для множества из этих причин. Каким образом вы предполагаете нам угадать, что вы передаете в эту функцию, существуют файлы, которые вы пытаетесь открывать, и что происходит в загадочной функции
0 |
|
IT_Exp Эксперт 87844 / 49110 / 22898 Регистрация: 17.06.2006 Сообщений: 92,604 |
23.01.2017, 22:12 |
|
Помогаю со студенческими работами здесь Segmentation fault Ребята чем отличается функция… Segmentation fault в релизе Pcap_close(): Segmentation fault Массив: Segmentation fault Искать еще темы с ответами Или воспользуйтесь поиском по форуму: 8 |
Вводная
C является «небезопасным» («unmanaged») языком, поэтому программы могут «вылетать» — аварийно завершать работу без сохранения данных пользователя, сообщения об ошибке и т.п. — стоит только, например, залезть в не инициализированную память. Например:
void fall()
{
char * s = "short_text";
sprintf(s,"This is very long text");
}
или
void fall()
{
int * pointer = NULL;
*pointer = 13;
}
Всем было бы лучше, если бы мы могли «отловить» падение программы — точно так же, как в java ловим исключения — и выполнить хоть что-то перед тем, как программа упадет (сохранить документ пользователя, вывести диалог с сообщением об ошибке и т.п.)
Общего решения задача не имеет, так как 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-совместимой ОС.

Когда я делаю ошибку в коде, то обычно это приводит к появлению сообщения “segmentation fault”, зачастую сокращённого до “segfault”. И тут же мои коллеги и руководство приходят ко мне: «Ха! У нас тут для тебя есть segfault для исправления!» — «Ну да, виноват», — обычно отвечаю я. Но многие ли из вас знают, что на самом деле означает ошибка “segmentation fault”?
Чтобы ответить на этот вопрос, нам нужно вернуться в далёкие 1960-е. Я хочу объяснить, как работает компьютер, а точнее — как в современных компьютерах осуществляется доступ к памяти. Это поможет понять, откуда же берётся это странное сообщение об ошибке.
Вся представленная ниже информация — основы компьютерной архитектуры. И без нужды я не буду сильно углубляться в эту область. Также я буду применять всем известную терминологию, так что мой пост будет понятен всем, кто не совсем на «вы» с вычислительной техникой. Если же вы захотите изучить вопрос работы с памятью подробнее, то можете обратиться к многочисленной доступной литературе. А заодно не забудьте покопаться в исходном коде ядра какой-нибудь ОС, например, Linux. Я не буду излагать здесь историю вычислительной техники, некоторые вещи не будут освещаться, а некоторые сильно упрощены.
Немного истории
Когда-то компьютеры были очень большими, весили тонны, при этом обладали одним процессором и памятью примерно на 16 Кб. Стоил такой монстр порядка $150 000 и мог выполнять лишь одну задачу за раз: в каждый момент времени выполнялся только один какой-то процесс. Архитектуру памяти в те времена можно схематически представить так:

То есть на ОС приходилась, скажем, четверть всей доступной памяти, а остальной объём отдавался под пользовательские задачи. В то время роль ОС заключалась в простом управлении оборудованием с помощью прерываний ЦПУ. Так что операционке нужна была память для себя, для копирования данных с устройств и для работы с ними (режим PIO). Для вывода данных на экран нужно было использовать часть основной памяти, ведь видеоподсистема либо не имела своей оперативки, либо обладала считанными килобайтами. А уже сама программа выполнялась в области памяти, идущей сразу после ОС, и решала свои задачи.
Совместный доступ к ресурсам
Главная проблема заключалась в том, что устройство, стоящее $150 000, было однозадачным и тратило целые дни на обработку нескольких килобайт данных.
Из-за непомерной стоимости мало кто мог позволить себе приобрести сразу несколько компьютеров, чтобы обрабатывать одновременно несколько задач. Поэтому люди начали искать способы совместного доступа к вычислительным ресурсам одного компьютера. Так наступила эра многозадачности. Обратите внимание, что в те времена ещё никто не помышлял о многопроцессорных компьютерах. Так как же можно заставить компьютер с одним ЦПУ выполнять несколько разных задач?
Решением стало использование планировщика задач (scheduling): пока один процесс прерывался, ожидая завершения операций ввода/вывода, ЦПУ мог выполнять другой процесс. Я не буду здесь больше касаться планировщика задач, это слишком обширная тема, не имеющая отношения к памяти.
Если компьютер способен поочерёдно выполнять несколько задач, то распределение памяти будет выглядеть примерно так:

Задачи А и В хранятся в памяти, поскольку копировать их на диск и обратно слишком затратно. И по мере того, как процессор выполняет ту или иную задачу, он обращается к памяти за соответствующими данными. Но тут возникает проблема.
Когда один программист будет писать код для выполнения задачи В, он должен знать границы выделяемых сегментов памяти. Допустим, задача В занимает в памяти отрезок от 10 до 12 Кб, тогда каждый адрес памяти должен быть жёстко закодирован в пределах этих границ. Но если компьютер будет выполнять сразу три задачи, то память будет поделена на большее количество сегментов, и значит сегмент для задачи В может оказаться сдвинут. Тогда код программы придётся переписывать, чтобы она могла оперировать меньшим объёмом памяти, а также изменить все указатели.
Здесь всплывает и иная проблема: что если задача В обратится к сегменту памяти, выделенному для задачи А? Такое легко может произойти, ведь при работе с указателями памяти достаточно сделать маленькую ошибку, и программа будет обращаться к совершенно другому адресу, нарушив целостность данных другого процесса. При этом задача А может работать с очень важными с точки зрения безопасности данными. Нет никакого способа помешать В вторгнуться в область памяти А. Наконец, вследствие ошибки программиста задача В может перезаписать область памяти ОС (в данном случае от 0 до 4 Кб).
Адресное пространство
Чтобы можно было спокойно выполнять несколько задач, хранящихся в памяти, нам нужна помощь от ОС и оборудования. В частности, адресное пространство. Это некая абстракция памяти, выделяемая ОС для какого-то процесса. На сегодняшний день это фундаментальная концепция, которая используется везде. По крайней мере, во ВСЕХ компьютерах гражданского назначения принят именно этот подход, а у военных могут быть свои секреты. Персоналки, смартфоны, телевизоры, игровые приставки, умные часы, банкоматы — ткните в любой аппарат, и окажется, что распределение памяти в нём осуществляется по принципу «код-стек-куча» (code-stack-heap).
Адресное пространство содержит всё, что нужно для выполнения процесса:
- Машинные инструкции, которые должен выполнить ЦПУ.
- Данные, с которыми будут работать эти машинные инструкции.
Схематически адресное пространство делится следующим образом:

- Стек (stack) — это область памяти, в которой программа хранит информацию о вызываемых функциях, их аргументах и каждой локальной переменной в функциях. Размер области может меняться по мере работы программы. При вызове функций стек увеличивается, а при завершении — уменьшается.
- Куча (heap) — это область памяти, в которой программа может делать всё, что заблагорассудится. Размер области может меняться. Программист имеет возможность воспользоваться частью памяти кучи с помощью функции
malloc(), и тогда эта область памяти увеличивается. Возврат ресурсов осуществляется с помощьюfree(), после чего куча уменьшается. - Кодовый сегмент (code) — это область памяти, в которой хранятся машинные инструкции скомпилированной программы. Они генерируются компилятором, но могут быть написаны и вручную. Обратите внимание, что эта область памяти также может быть разделена на три части (текст, данные и BSS). Эта область памяти имеет фиксированный размер, определяемый компилятором. В нашем примере пусть это будет 1 Кб.
Поскольку стек и куча могут меняться в размерах, они размещены в противоположных частях общего адресного пространства. Направления изменения их размеров показаны стрелками. В обязанности ОС входит контроль над тем, чтобы эти области не наложились друг на друга.
Виртуализация памяти
Допустим, задача А получила в своё распоряжение всю доступную пользовательскую память. И тут возникает задача В. Как быть? Решение было найдено в виртуализации.
Напомню одну из предыдущих иллюстраций, когда в памяти одновременно находятся А и В:

Допустим, А пытается получить доступ к памяти в собственном адресном пространстве, например по индексу 11 Кб. Возможно даже, что это будет её собственный стек. В этом случае ОС нужно придумать, как не подгружать индекс 1500, поскольку по факту он может указывать на область задачи В.
На самом деле, адресное пространство, которое каждая программа считает своей памятью, является памятью виртуальной. Фальшивкой. И в области памяти задачи А индекс 11 Кб будет фальшивым адресом. То есть — адресом виртуальной памяти.
Каждая программа, выполняющаяся на компьютере, работает с фальшивой (виртуальной) памятью. С помощью некоторых чипов ОС обманывает процесс, когда он обращается к какой-либо области памяти. Благодаря виртуализации ни один процесс не может получить доступ к памяти, которая ему не принадлежит: задача А не влезет в память задачи В или самой ОС. При этом на пользовательском уровне всё абсолютно прозрачно, благодаря обширному и сложному коду ядра ОС.
Таким образом, каждое обращение к памяти регулируется операционной системой. И это должно осуществляться очень эффективно, чтобы не слишком замедлять работу различных выполняющихся программ. Эффективность обеспечивается с помощью аппаратных средств, преимущественно — ЦПУ и некоторых компонентов вроде MMU. Последний появился в виде отдельного чипа в начале 1970-х, а сегодня MMU встраиваются непосредственно в процессор и в обязательном порядке используются операционными системами.
Вот небольшая программка на С, демонстрирующая работу с адресами памяти:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int v = 3;
printf("Code is at %p n", (void *)main);
printf("Stack is at %p n", (void *)&v);
printf("Heap is at %p n", malloc(8));
return 0;
}
На моей машине LP64 X86_64 она показывает такой результат:
Code is at 0x40054c
Stack is at 0x7ffe60a1465c
Heap is at 0x1ecf010
Как я и описывал, сначала идёт кодовый сегмент, затем куча, а затем стек. Но все эти три адреса фальшивые. В физической памяти по адресу 0x7ffe60a1465c вовсе не хранится целочисленная переменная со значением 3. Никогда не забывайте, что все пользовательские программы манипулируют виртуальными адресами, и только на уровне ядра или аппаратных драйверов допускается использование адресов физической памяти.
Переадресация
Переадресация (транслирование, перевод, преобразование адресов) — это термин, обозначающий процесс сопоставления виртуального адреса физическому. Занимается этим модуль MMU. Для каждого выполняющегося процесса операционка должна помнить соответствия всех виртуальных адресов физическим. И это довольно непростая задача. По сути, ОС приходится управлять памятью каждого пользовательского процесса при каждом обращении. Тем самым она превращает кошмарную реальность физической памяти в полезную, мощную и лёгкую в использовании абстракцию.
Давайте рассмотрим подробнее.
Когда запускается процесс, ОС бронирует для него фиксированный объём физической памяти, пусть это будет 16 Кб. Начальный адрес этого адресного пространства сохраняется в специальной переменной base. А в переменной bounds записывается размер выделенной области памяти, в нашем примере — 16 Кб. Эти два значения записываются в каждую таблицу процессов — PCB (Process Control Block).
Итак, это виртуальное адресное пространство:

А это его физический образ:

ОС решает выделить диапазон физических адресов от 4 до 20 Кб, то есть значение base равно 4 Кб, а значение bounds равно 4 + 16 = 20 Кб. Когда процесс ставится в очередь на выполнение (ему выделяется процессорное время), ОС считывает из PCB значения обеих переменных и копирует их в специальные регистры ЦПУ. Далее процесс запускается и пытается обратиться, допустим, к виртуальному адресу 2 Кб (в своей куче). К этому адресу ЦПУ добавляет значение base, полученное от ОС. Следовательно, физический адрес будет 2+ 4 = 6 Кб.
Физический адрес = виртуальный адрес + base
Если получившийся физический адрес (6 Кб) выбивается из границ выделенной области (4—20 Кб), это означает, что процесс пытается обратиться к памяти, которая ему не принадлежит. Тогда ЦПУ генерирует исключение и сообщает об этом ОС, которая обрабатывает данное исключение. В этом случае система обычно сигнализирует процессу о нарушении: SIGSEGV, Segmentation Fault. Этот сигнал по умолчанию прерывает выполнение процесса (это можно настраивать).
Перераспределение памяти
Если задача А исключена из очереди на выполнение, то это даже лучше. Это означает, что планировщик попросили выполнить другую задачу (допустим, В). Пока выполняется В, операционка может перераспределить всё физическое пространство задачи А. Во время выполнения пользовательского процесса ОС зачастую теряет управление процессором. Но когда процесс делает системный вызов, процессор снова возвращается под контроль ОС. До этого системного вызова операционка может что угодно делать с памятью, в том числе и целиком перераспределять адресное пространство процесса в другой физический раздел.
В нашем примере это осуществляется достаточно просто: ОС перемещает 16-килобайтную область в другое свободное место подходящего размера и просто обновляет значения переменных base и bounds для задачи А. Когда процессор возвращается к её выполнению, процесс переадресации всё ещё работает, но физическое адресное пространство уже изменилось.
С точки зрения задачи А ничего не меняется, её собственное адресное пространство по-прежнему расположено в диапазоне 0-16 Кб. При этом ОС и MMU полностью контролируют каждое обращение задачи к памяти. То есть программист манипулирует виртуальной областью 0-16 Кб, а MMU берёт на себя сопоставление с физическими адресами.
После перераспределения образ памяти будет выглядеть так:

Программисту теперь не нужно заботиться о том, с какими адресами памяти будет работать его программа, не нужно переживать о конфликтах. ОС в связке с MMU снимают с него все эти заботы.
Сегментация памяти
В предыдущих главах мы рассмотрели вопросы переадресации и перераспределения памяти. Однако у нашей модели работы с памятью есть ряд недостатков:
- Мы предполагаем, что каждое виртуальное адресное пространство имеет размер в 16 Кб. Это не имеет никакого отношения к действительности.
- ОС приходится поддерживать список свободных диапазонов физической памяти размером по 16 Кб, чтобы выделять их для новых запускаемых процессов или перераспределения текущих выделенных областей. Как можно эффективно осуществлять всё это, не ухудшив производительность всей системы?
- Мы выделяем по 16 Кб каждому процессу, но ведь не факт, что каждый из них будет использовать всю выделенную область. Так что мы просто теряем кучу памяти на пустом месте. Это называется внутренней фрагментацией (internal fragmentation) — память резервируется, но не используется.
Для решения некоторых из этих проблем давайте рассмотрим более сложную систему организации памяти — сегментацию. Смысл её прост: принцип “base and bounds” распространяется на все три сегмента памяти — кучу, кодовый сегмент и стек, причём для каждого процесса, вместо того чтобы рассматривать образ памяти как единую уникальную сущность.
В результате мы больше не теряем память между стеком и кучей:

Как вы могли заметить, свободное пространство в виртуальной памяти задачи А больше не размещено в памяти физической. И память теперь используется гораздо эффективнее. ОС теперь должна запоминать для каждой задачи три пары base и bounds, по одной для каждого сегмента. MMU, как и раньше, занимается переадресацией, но оперирует уже тремя baseи тремя
bounds.
Допустим, у кучи задачи А параметр base равен 126 Кб, а bounds — 2 Кб. Пусть задача А обращается к виртуальному адресу 3 Кб (в куче). Тогда физический адрес определяется как 3 – 2 Кб (начало кучи) = 1 Кб + 126 Кб (сдвиг) = 127 Кб. Это меньше 128, а значит ошибки обращения не будет.
Совместное использование сегментов
Сегментирование физической памяти не только не позволяет виртуальной памяти отъедать физическую, но также даёт возможность совместного использования физических сегментов с помощью виртуальных адресных пространств разных процессов.
Если дважды запустить задачу А, то кодовый сегмент у них будет один и тот же: в обеих задачах выполняются одинаковые машинные инструкции. В то же время у каждой задачи будут свои стек и куча, поскольку они оперируют разными наборами данных.

При этом оба процесса не подозревают, что делят с кем-то свою память. Такой подход стал возможен благодаря внедрению битов защиты сегмента (segment protection bits).
Для каждого создаваемого физического сегмента ОС регистрирует значение bounds, которое используется MMU для последующей переадресации. Но в то же время регистрируется и так называемый флаг разрешения (permission flag).
Поскольку сам код нельзя модифицировать, то все кодовые сегменты создаются с флагами RX. Это значит, что процесс может загружать эту область памяти для последующего выполнения, но в неё никто не может записывать. Другие два сегмента — куча и стек — имеют флаги RW, то есть процесс может считывать и записывать в эти свои два сегмента, однако код из них выполнять нельзя. Это сделано для обеспечения безопасности, чтобы злоумышленник не мог повредить кучу или стек, внедрив в них свой код для получения root-прав. Так было не всегда, и для высокой эффективности этого решения требуется аппаратная поддержка. В процессорах Intel это называется “NX bit”.
Флаги могут быть изменены в процессе выполнения программы, для этого используется mprotect().
Под Linux все эти сегменты памяти можно посмотреть с помощью утилит /proc/{pid}/maps или /usr/bin/pmap.
Вот пример на PHP:
$ pmap -x 31329
0000000000400000 10300 2004 0 r-x-- php
000000000100e000 832 460 76 rw--- php
00000000010de000 148 72 72 rw--- [ anon ]
000000000197a000 2784 2696 2696 rw--- [ anon ]
00007ff772bc4000 12 12 0 r-x-- libuuid.so.0.0.0
00007ff772bc7000 1020 0 0 ----- libuuid.so.0.0.0
00007ff772cc6000 4 4 4 rw--- libuuid.so.0.0.0
... ...
Здесь есть все необходимые подробности относительно распределения памяти. Адреса виртуальные, отображаются разрешения для каждой области памяти. Каждый совместно используемый объект (.so) размещён в адресном пространстве в виде нескольких частей (обычно код и данные). Кодовые сегменты являются исполняемыми и совместно используются в физической памяти всеми процессами, которые разместили подобный совместно используемый объект в своём адресном пространстве.
Shared Objects — это одно из крупнейших преимуществ Unix- и Linux-систем, обеспечивающее экономию памяти.
Также с помощью системного вызова mmap() можно создавать совместно используемую область, которая преобразуется в совместно используемый физический сегмент. Тогда у каждой области появится индекс s, означающий shared.
Ограничения сегментации
Итак, сегментация позволила решить проблему неиспользуемой виртуальной памяти. Если она не используется, то и не размещается в физической памяти благодаря использованию сегментов, соответствующих именно объёму используемой памяти.
Но это не совсем верно.
Допустим, процесс запросил у кучи 16 Кб. Скорее всего, ОС создаст в физической памяти сегмент соответствующего размера. Если пользователь потом освободит из них 2 Кб, тогда ОС придётся уменьшить размер сегмента до 14 Кб. Но вдруг потом программист запросит у кучи ещё 30 Кб? Тогда предыдущий сегмент нужно увеличить более чем в два раза, а возможно ли это будет сделать? Может быть, его уже окружают другие сегменты, не позволяющие ему увеличиться. Тогда ОС придётся искать свободное место на 30 Кб и перераспределять сегмент.

Главный недостаток сегментов заключается в том, что из-за них физическая память сильно фрагментируется, поскольку сегменты увеличиваются и уменьшаются по мере того, как пользовательские процессы запрашивают и освобождают память. А ОС приходится поддерживать список свободных участков и управлять ими.
Фрагментация может привести к тому, что какой-нибудь процесс запросит такой объём памяти, который будет больше любого из свободных участков. И в этом случае ОС придётся отказать процессу в выделении памяти, даже если суммарный объём свободных областей будет существенно больше.
ОС может попытаться разместить данные компактнее, объединяя все свободные области в один большой чанк, который в дальнейшем можно использовать для нужд новых процессов и перераспределения.

Но подобные алгоритмы оптимизации сильно нагружают процессор, а ведь его мощности нужны для выполнения пользовательских процессов. Если ОС начинает реорганизовывать физическую память, то система становится недоступной.
Так что сегментация памяти влечёт за собой немало проблем, связанных с управлением памятью и многозадачностью. Нужно как-то улучшить возможности сегментации и исправить недостатки. Это достигается с помощью ещё одного подхода — страниц виртуальной памяти.
Разбиение памяти на страницы
Как было сказано выше, главный недостаток сегментации заключается в том, что сегменты очень часто меняют свой размер, и это приводит к фрагментации памяти, из-за чего может возникнуть ситуация, когда ОС не выделит для процессов нужные области памяти. Эта проблема решается с помощью страниц: каждое размещение, которое ядро делает в физической памяти, имеет фиксированный размер. То есть страницы — это области физической памяти фиксированного размера, ничего более. Это сильно облегчает задачу управления свободным объёмом и избавляет от фрагментации.
Давайте рассмотрим пример: виртуальное адресное пространство объёмом 16 Кб разбито на страницы.

Мы не говорим здесь о куче, стеке или кодовом сегменте. Просто делим память на куски по 4 Кб. Затем то же самое делаем с физической памятью:

ОС хранит таблицу страниц процесса (process page table), в которой представлены взаимосвязи между страницей виртуальной памяти процесса и страницей физической памяти (страничный кадр, page frame).

Теперь мы избавились от проблемы поиска свободного места: страничный кадр либо используется, либо нет (unused). И ядру не в пример легче найти достаточное количество страниц, чтобы выполнить запрос процесса на выделение памяти.
Страница — это мельчайшая и неделимая единица памяти, которой может оперировать ОС.
У каждого процесса есть своя таблица страниц, в которой представлена переадресация. Здесь уже используются не значения границ области, а номер виртуальной страницы (VPN, virtual page number) и сдвиг (offset).
Пример: размер виртуального пространства 16 Кб, следовательно, нам нужно 14 бит для описания адресов (214 = 16 Кб). Размер страницы 4 Кб, значит нам нужно 4 Кб (16/4), чтобы выбрать нужную страницу:

Когда процесс хочет использовать, например, адрес 9438 (вне границ 16 384), то он запрашивает в двоичном коде 10.0100.1101.1110:

Это 1246-й байт в виртуальной странице номер 2 («0100.1101.1110»-й байт в «10»-й странице). Теперь ОС достаточно просто обратиться к таблице страниц процесса, чтобы найти эту страницу номер 2. В нашем примере она соответствует восьмитысячному байту физической памяти. Следовательно, виртуальный адрес 9438 соответствует физическому адресу 9442 (8000 + сдвиг 1246).
Как уже было сказано, каждый процесс обладает лишь одной таблицей страниц, поскольку у каждого процесса собственная переадресация, как и у сегментов. Но где же именно хранятся все эти таблицы? Наверное, в физической памяти, где же ещё им быть?
Если сами таблицы страниц хранятся в памяти, то для получения VPN надо обращаться к памяти. Тогда количество обращений к ней удваивается: сначала мы извлекаем из памяти номер нужной страницы, а затем обращаемся к самим данным, хранящимся в этой странице. И если скорость доступа к памяти невелика, то ситуация выглядит довольно грустно.
Буфер быстрой переадресации (TLB, Translation-lookaside Buffer)
Использование страниц в качестве основного инструмента поддержки виртуальной памяти может привести к сильному снижению производительности. Разбиение адресного пространства на небольшие куски (страницы) требует хранения большого количества данных о размещении страниц. А раз эти данные хранятся в памяти, то при каждом обращении процесса к памяти осуществляется ещё одно, дополнительное обращение.
Для поддержания производительности снова используется помощь оборудования. Как и при сегментации, мы аппаратными методами помогаем ядру эффективно осуществлять переадресацию. Для этого используется TLB, входящий в состав MMU, и представляющий собой простой кэш для некоторых VPN-переадресаций. TLB позволяет ОС не обращаться к памяти лишний раз, чтобы получить физический адрес из виртуального.
Аппаратный MMU инициируется при каждом обращении к памяти, извлекает из виртуального адреса VPN и запрашивает у TLB, хранится ли в нём переадресация с этого VPN. Если да, то его роль выполнена. Если нет, то MMU находит нужную таблицу страниц процесса, и если она ссылается на валидный адрес, то обновляет данные в TLB, чтобы тот предоставлял их при следующем обращении.
Как вы понимаете, если в кэше отсутствует нужная переадресация, то это замедляет обращение к памяти. Можно предположить, что чем больше размер страниц, тем больше вероятность, что в TLB окажутся нужные данные. Но тогда мы будем тратить больше памяти на каждую страницу. Так что здесь нужен какой-то компромисс. Современные ядра умеют использовать страницы разных размеров. Например, Linux способен оперировать «огромными» страницами по 2 Мб вместо традиционных 4 Кб.
Также рекомендуется хранить данные компактно, в смежных адресах памяти. Если вы раскидаете их по всей памяти, то куда чаще в TLB не будет обнаруживаться нужной переадресации, либо он будет постоянно переполняться. Это называется эффективностью пространственной локальности (spacial locality efficiency): данные, которые расположены в памяти сразу за вашими, могут размещаться в той же физической странице, и тогда благодаря TLB вы получите выигрыш в производительности.
Кроме того, TLB в каждой записи хранит так называемые ASID (Address Space Identifier, идентификатор адресного пространства). Это нечто вроде PID, идентификатора процесса. Каждый процесс, поставленный в очередь на выполнение, имеет собственный ASID, и TLB может управлять обращением любого процесса к памяти, без риска ошибочных обращений со стороны других процессов.
Повторимся снова: если пользовательский процесс пытается обратиться к неправильному адресу, тот наверняка будет отсутствовать в TLB. Следовательно, будет запущена процедура поиска в таблице страниц процесса. В ней хранится переадресация, но с неправильным набором битов. В х86-системах переадресации имеют размер 4 Кб, то есть битов в них немало. А значит есть вероятность найти правильный бит, равно как и другие вещи, наподобие бита изменения («грязного бита», dirty bit), битов защиты (protection bit), бита обращения (reference bit) и т.д. И если запись помечена как неправильная, то ОС по умолчанию выдаст SIGSEGV, что приведёт к ошибке “segmentation fault”, даже если о сегментах уже и речи не идёт.
На самом деле разбиение памяти на страницы в современных ОС устроено куда сложнее, чем я расписал. В частности, используются многоуровневые записи в таблицах страниц, многостраничные размеры, вытеснение страниц (page eviction), также известное как «обмен» (ядро скидывает страницы из памяти на диск и обратно, что повышает эффективность использования основной памяти и создаёт у процессов иллюзию её неограниченности).
Заключение
Теперь вы знаете, что стоит за сообщением “segmentation fault”. Раньше операционки использовали сегменты для размещения пространства виртуальной памяти в пространстве физической. Когда пользовательский процесс хочет обратиться к памяти, то он просит MMU переадресовать его. Но если полученный адрес ошибочен, — находится вне пределов физического сегмента, или если сегмент не имеет нужных прав (попытка записи в read only-сегмент), — то ОС по умолчанию отправляет сигнал SIGSEGV, что приводит к прерыванию выполнения процесса и выдаче сообщения “segmentation fault”. В каких-то ОС это может быть “General protection fault”. Вы можете изучить исходный код Linux для х86/64-платформ, отвечающий за ошибки доступа к памяти, в частности — за SIGSEGV. Также можете посмотреть, как на этой платформе осуществляется сегментирование. Вы откроете для себя интересные моменты относительно разбиения на страницы, дающие куда больше возможностей, чем при использовании классических сегментов.
Programming languages like C and C++ manage the memory in a more direct way than other programming languages like Java, C#, Python, etc. When an application tries to access the memory area that it does not belong to it Segmentation Fault occurs. Generally, the segmentation fault resulted in the core being dumped which is saving the error memory area into a file for later investigation. There are different reasons for the “Segmentation Fault”/”Core Dumped” error like below.
- Modifying String Literal
- Accessing Freed Address
- Accessing Out Of Array Index Bounds
- Improper useof scanf() Function
- Stackoverflow
- Dereferencing Uninitialized Pointer
Modifying String Literal
String literals are stored in a read-only part of the application. String literals can not be edited as they are located in the read-only part of memory. When the string literal is tried to be changed the segmentation fault occurs and the core is dumped with the Abnormal termination of program .
int main()
{
char *s;
/* Stored in read only part of application memory */
s = "wt";
/* Problem: trying to modify read only memory */
*(s+1) = 'x';
return 0;
}
Accessing Freed Address
Pointers are used to allocated memory parts with memory addresses. After usage, the memory areas or addresses are freed and the freed address range can not be used. If the application tries to access the free address locations the “core dump” error occurs.
int main()
{
char* s= (int*) malloc(8*sizeof(int));
*s = 10;
//s memory area is freed
free(s);
//Try to access free memory are
*s = 20;
return 0;
}
Accessing Out Of Array Index Bounds
C and C++ programming languages provide arrays in order to store multiple characters and values inside a single variable. The size of the arrays should be set during initialization and the memory area is allocated according to its size. If the application tries to access of range memory area of the array the “core dump” error occurs.
int main()
{
char s[3]="abc";
s[5]="d";
return 0;
}
Improper useof scanf() Function
The scanf() function is used to read user input from the standard input interactively. The scanf() function requires the memory address of a variable in order to store read value If the address is not provided properly or read-only.
int main()
{
char s[3];
scanf("%s",&s+1)
return 0;
}
StackOverflow
Every application has a limited memory area called the stack. The stack area is used to store data temporarily during the execution of the application when functions are called. When the stack area is filled and there is no free area the StackOverflow occurs. The stack overflow generally occurs in error-prone algorithms like using recursive functions infinitely.
int main()
{
rec();
}
int rec()
{
int a = 5;
rec();
}
Dereferencing Uninitialized Pointer
Pointers are used to point to specific memory addresses. In order to use a pointer, it should be initialized before accessing or dereferencing it. Without initialization, the pointer does not point to any memory area or data which can not be used.
int main()
{
int* a;
printf("%d",*a);
return 0;
}
Improve Article
Save Article
Improve Article
Save Article
Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.”
- When a piece of code tries to do read and write operation in a read only location in memory or freed block of memory, it is known as core dump.
- It is an error indicating memory corruption.
Common segmentation fault scenarios:
- Modifying a string literal :
The below program may crash (gives segmentation fault error) because the line *(str+1) = ‘n’ tries to write a read only memory.
C++
#include <iostream>
using namespace std;
int main()
{
char *str;
str = "GfG";
*(str + 1) = 'n';
return 0;
}
C
int main()
{
char *str;
str = "GfG";
*(str+1) = 'n';
return 0;
}
Abnormal termination of program.
Refer Storage for Strings in C for details
- Accessing an address that is freed :
Here in the below code, the pointer p is dereferenced after freeing the memory block, which is not allowed by the compiler. So it produces the error segment fault or abnormal program termination at runtime.
Example:
C++
#include <iostream>
using namespace std;
int main(void)
{
int* p = (int*) malloc(8*sizeof(int));
*p = 100;
free(p);
*p = 110;
return 0;
}
C
#include <stdio.h>
#include<alloc.h>
int main(void)
{
int* p = malloc(8);
*p = 100;
free(p);
*p = 110;
return 0;
}
Output:
Abnormal termination of program.
- Accessing out of array index bounds :
CPP
#include <iostream>
using namespace std;
int main()
{
int arr[2];
arr[3] = 10;
return 0;
}
C
#include <stdio.h>
int main(void)
{
int arr[2];
arr[3] = 10;
return (0);
}
Output:
Abnormal termination of program.
- Improper use of scanf() :
scanf() function expects address of a variable as an input. Here in this program n takes
value of 2 and assume it’s address as 1000. If we pass n to scanf(), input fetched from STDIN is placed in invalid memory 2 which should be 1000 instead. It’s a memory corruption leading to Segmentation fault.
C++
#include <iostream>
using namespace std;
int main()
{
int n = 2;
cin >> " " >> n;
return 0;
}
C
#include <stdio.h>
int main()
{
int n = 2;
scanf(" ",n);
return 0;
}
Output:
Abnormal termination of program.
- Stack Overflow
It’s not a pointer related problem even code may not have single pointer. It’s because of recursive function gets called repeatedly which eats up all the stack memory resulting in stack overflow. Running out of memory on the stack is also a type of memory corruption. It can be resolved by having a base condition to return from the recursive function.
- Dereferencing uninitialized pointer
A pointer must point to valid memory before accessing it.
C++14
#include <iostream>
using namespace std;
int main()
{
int* p;
cout << *p;
return 0;
}
C
#include <stdio.h>
int main()
{
int *p;
printf("%d",*p);
return 0;
}
This article is contributed by Bishal Kumar Dubey. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

This error may strike your Ubuntu at any point at the moment. A few days ago when I was doing my routine work in my Ubuntu laptop, suddenly I encountered with an error “Segmentation fault ( core dumped)” then I got to know that, this error can strike you Ubuntu or any other operating system at any point of the moment as binaries crashing doesn’t depend on us.
Segmentation fault is when your system tries to access a page of memory that doesn’t exist. Core dumped means when a part of code tries to perform read and write operation on a read-only or free location. Segfaults are generally associated with the file named core and It generally happens during up-gradation.
While running some commands during the core-dump situation you may encounter with “Unable to open lock file” this is because the system is trying to capture a bit block which is not existing, This is due to the crashing of binaries of some specific programs.
You may do backtracking or debugging to resolve it but the solution is to repair the broken packages and we can do it by performing the below-mentioned steps:
Command-line:
Step 1: Remove the lock files present at different locations.
sudo rm -rf /var/lib/apt/lists/lock /var/cache/apt/archives/lock /var/lib/dpkg/lock and restart your system h.cdccdc
Step 2: Remove repository cache.
Step 3: Update and upgrade your repository cache.
sudo apt-get update && sudo apt-get upgrade
Step 4: Now upgrade your distribution, it will update your packages.
sudo apt-get dist-upgrade
Step 5: Find the broken packages and delete them forcefully.
sudo dpkg -l | grep ^..r | apt-get purge
Apart from the command line, the best way which will always work is:
Step 1: Run Ubuntu in startup mode by pressing the Esc key after the restart.
Step 2: Select Advanced options for Ubuntu
Step 3: Run Ubuntu in the recovery mode and you will be listed with many options.
Step 4: First select “Repair broken packages”
Step 5: Then select “Resume normal boot”
So, we have two methods of resolving segmentation fault: CLI and the GUI. Sometimes, it may also happen that the “apt” command is not working because of segfault, so our CLI method will not work, in that case also don’t worry as the GUI method gonna work for us always.


