The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  ВХОД  слежка  RSS
"catch для segmentation fault"
Вариант для распечатки  
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [Проследить за развитием треда]

"catch для segmentation fault"  
Сообщение от L email(??) on 22-Янв-07, 21:38 
Подскажите, есть ли способ обработать ошибку "segmentation fault"? Ошибка возникает при попытке удаления по адресу, который уже не принадлежит текущей thread.
catch это не отлавливает.
Или может быть есть способ определить, кому принадлежит конкретный адрес памяти - текущей thread или кому-то другому?
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

 Оглавление

Сообщения по теме [Сортировка по времени, UBB]


1. "catch для segmentation fault"  
Сообщение от BigHo on 22-Янв-07, 21:48 
>Подскажите, есть ли способ обработать ошибку "segmentation fault"? Ошибка возникает при попытке
>удаления по адресу, который уже не принадлежит текущей thread.
>catch это не отлавливает.
>Или может быть есть способ определить, кому принадлежит конкретный адрес памяти -
>текущей thread или кому-то другому?

Это территория gdb. Иногда стек бывает порчен, и узнать не удается ничего (особенно, если несколько потоков). Но если повезет.. Для некоторых систем код требуется собрать с опциями -g -fPIC. И уж точно отключит оптимизацию (-O0).

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

2. "catch для segmentation fault"  
Сообщение от L email(??) on 22-Янв-07, 22:36 
>(особенно, если несколько потоков). Но если повезет.. Для некоторых систем код
>требуется собрать с опциями -g -fPIC. И уж точно отключит оптимизацию (-O0).
Не получилось... на Linux FC4 с gcc, выдает все так же
*** glibc detected *** ./test: double free or corruption (fasttop): 0x08383288 ***
Но все равно спасибо.


Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

3. "catch для segmentation fault"  
Сообщение от L email(??) on 22-Янв-07, 22:44 
Это даже без thread, чисто тест:
delete p;
cout << "delete 1" << endl;
try {
    delete p;
}
catch (...) {
    cout << "delete 2 error" << endl;
}
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

4. "catch для segmentation fault"  
Сообщение от Michelnok (ok) on 22-Янв-07, 22:49 
>Или может быть есть способ определить, кому принадлежит конкретный адрес памяти -
>текущей thread или кому-то другому?

У потоков нет понятия принадлежности им адресов памяти.
Адресное пространство разделяется только между процессами.

А за delete одного и того же объекта два раза надо отрывать руки. С корнем.
Если не согласны - Java или .NET вам в руки.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

5. "catch для segmentation fault"  
Сообщение от L email(??) on 22-Янв-07, 23:15 
>А за delete одного и того же объекта два раза надо отрывать
>руки. С корнем.

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

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

6. "catch для segmentation fault"  
Сообщение от Michelnok (ok) on 23-Янв-07, 02:00 
>Проблема не в двойном удалении объекта, а в том что он удаляется
>потоком, которому он уже не принадлежит. В данном тесте попытка дважды
>удалить - это приблизительное воспроизведение ситуации.

Еще раз. Нет такого понятия, как принадлежность объекта потоку (про thread local storage мы сейчас не говорим). Попытка дважды удалить один и тот же обьект - это недостаток проектирования. Если нечто подобное в программе ДЕЙСТВИТЕЛЬНО надо, то:

delete p;
p=NULL; // !!!!!!!!!!
cout << "delete 1" << endl;
...
// тут мы что-то делаем, причем далее не факт что когда-то уже был delete,
// поэтому надо его вызвать
try {
    delete p; // delete NULL не имеет никакого эффекта, см. стандарт на язык C++
}
catch (...) {
    cout << "delete 2 error" << endl;
}

А за решение с catch я бы оторвал руки второй раз. Почему? Это тебе домашнее задание :)

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

7. "catch для segmentation fault"  
Сообщение от L email(??) on 25-Янв-07, 00:25 
>А за решение с catch я бы оторвал руки второй раз.

Можешь и себе оторвать, и не только руки, но и язык :)
Еще раз объясняю ситуацию: работают несколько thread, каждая перед самым завершением вызывает delete 1 РАЗ. Пытаюсь разобраться в чем может быть причина того что время от времени (достаточно редко чтобы собрать статистику, раза 2-3) сервер вдруг падает. Каждый раз это происходит при большой загрузке сервера и в последние два раза удалось зафиксировать только то что у двух разных клиентов оказались в некоторый момент времени одинаковые адреса указателя на сокет (не сами дескрипторы!). В общем-то это странно, т.к. каждая thread создает свой экземпляр класса например A, который содержит этот самый указатель на сокет. Причем один клиент в этот момент начинал процедуру отката из-за временных проблем с сетью, а второй только пытался присоединиться, но при этом объект класса A уже создан.
Последовательность лога оказалась такая:
-первый получил некорректные данные из сети, собирается отключиться
-второй пытается присоединиться, сетевая ошибка, отсоединяется
-первый отсоединился


Это первое... А второе - прежде чем что-то сказать, читай теорию. close не закрывает сокет, а только уменьшает на единицу счетчик количества указателей на этот сокет. А вот если этот счетчик окажется равным 0, то тогда действительно закроет, а если еще не 0, то сокет будет продолжать работать.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

8. "catch для segmentation fault"  
Сообщение от Forth (??) on 25-Янв-07, 09:25 
>Это первое... А второе - прежде чем что-то сказать, читай теорию. close
>не закрывает сокет, а только уменьшает на единицу счетчик количества указателей
>на этот сокет. А вот если этот счетчик окажется равным 0,
>то тогда действительно закроет, а если еще не 0, то сокет
>будет продолжать работать.
Не на сокет, а на объект в ядре. Если допустим один процесс открыл файл, а другой этот файл удалил, то у первого ничего ужасного не произойдет, файл все равно открыт и связан с сокетом, а вот когда он его закроет - файл будет удален. Иными словами если сокет закрыт в процессе с помощью close() - дескриптор уже ни на что не указывает.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

9. "catch для segmentation fault"  
Сообщение от L email(??) on 25-Янв-07, 18:59 
>Если допустим один процесс
>открыл файл, а другой этот файл удалил, то у первого ничего
>ужасного не произойдет, файл все равно открыт и связан с сокетом,
>а вот когда он его закроет - файл будет удален. Иными
>словами если сокет закрыт в процессе с помощью close() - дескриптор
>уже ни на что не указывает.

Да, я понимаю что close сам по себе большой роли не сыграет. Но что произойдет если объект класса Socket (в нем не только дескриптор сокета) открыт через new, и thread имеет указатель *p на этот объект. Если предположить что в результате какого-то сбоя в памяти вторая thread получила свой *p по тому же адресу, то [delete p] во второй thread  получается пытается удалить общий на данный момент участок, в том числе и сокет, который еще использует первая thread. Хотя конечно это только гипотеза, а в log не оказалось сообщения об ошибке, несмотря на запуск ... 1>>log 2>>log

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

10. "catch для segmentation fault"  
Сообщение от Michelnok (ok) on 25-Янв-07, 20:59 

>у двух разных клиентов оказались в некоторый момент времени одинаковые адреса указателя

Вот это и есть ошибка. И решать ее надо совсем не catch'ем.

>close
>не закрывает сокет, а только уменьшает на единицу счетчик количества указателей
>на этот сокет. А вот если этот счетчик окажется равным 0,
>то тогда действительно закроет, а если еще не 0, то сокет
>будет продолжать работать.

Даа? Ну, спасибо что просветил. А как увеличить "счетчик количества указателей"? Именно это ты, наверное, и делаешь? Ведь чтобы уменьшить два раза, надо сначала увеличить два раза...

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

11. "catch для segmentation fault"  
Сообщение от L email(??) on 25-Янв-07, 22:40 
>>у двух разных клиентов оказались в некоторый момент времени одинаковые адреса указателя
>Вот это и есть ошибка. И решать ее надо совсем не catch'ем.
Естественно ошибка, но run-time, а воспроизвести ее никак не удается, т.к. в нормальной ситуации адреса разные:
========================
class Socket { ...}

class A {
....
Socket* socket_;
....
~A() {...  delete socket_;};
}
========================
Socket* current_socket;

void StartThread() {
  создается объект класса A(current_socket)
  ..... обработка ......
}

....
boost::thread_group threads;
boost::function0<void> f = &StartThread;
.....
while (...есть клиент...) {
     Socket* p=new Socket(...);
     current_socket = p;
     threads.create(f);
}
....
Вот и получается, что если не воспроизвести, то либо проблема не в этом, либо это была проблема системы, а не сервера, тогда надо просто как-то учесть вероятность, что это опять произойдет.

>Даа? Ну, спасибо что просветил. А как увеличить "счетчик количества указателей"? Именно
>это ты, наверное, и делаешь? Ведь чтобы уменьшить два раза, надо
>сначала увеличить два раза...
Y меня только гипотеза, что в какой-то момент система раз уж отвела один и тот же адрес под указатели из разных thread, то возможно выдала тот же дескриптор сокета для второй thread, и тогда счетчик мог увеличиться на 1.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

12. "catch для segmentation fault"  
Сообщение от Michelnok (ok) on 26-Янв-07, 02:00 
>Вот и получается, что если не воспроизвести, то либо проблема не в
>этом, либо это была проблема системы, а не сервера, тогда надо
>просто как-то учесть вероятность, что это опять произойдет.

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

В приведенном тобой коде я вижу одну ошибку. Возможно это и есть причина (по-крайней мере, последствия могут быть именно такие как ты описал). Глобальная переменная current_socket, фактически передаваемая как параметр потоку. Смотри что будет в следующем сценарии:

Сначала выполняется это:

Socket* p=new Socket(...);
current_socket = p;
threads.create(f);

Затем не факт что StartThread нового потока уже заработала. Особенно не факт - на однопроцессорной машине. Вполне может быть такое что время потока, делающего while не истекло, система не переключила процессор на новый поток, и основной поток пошел на новый шаг цикла (допустим что из-за большой нагрузке у нас уже есть еще один клиент):

Socket* p=new Socket(...);
current_socket = p;
threads.create(f);

Что мы имеем после этого? Переменная current_socket переписана. Тот объект (Socket), который был создан на предыдущем шаге цикла, фактически потерян. А оба новосозданных потока будут работать С ОДНИМ И ТЕМ ЖЕ объектом Socket, созданным на втором шаге цикла.
Вот и проблема. Двойное его удаление - это лишь следствие.

Я не работал с библиотекой boost. Там что, действительно нельзя передать параметр потоку при его создании? Ты бы решил проблему, избавившись от глобальной переменной.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

13. "catch для segmentation fault"  
Сообщение от Michelnok (ok) on 26-Янв-07, 02:42 
>Я не работал с библиотекой boost. Там что, действительно нельзя передать параметр
>потоку при его создании?

Нда... Посмотрел я на этот boost и на его реализацию потоков. Редкая гадость. Параметр там действительно нельзя передать. В качестве параметра потока (который есть во всех нормальных реализациях потоков) они уже используют указатель на некий внутренний объект thread_param. Что интересно, объект thread_param они создают как локальный в конструкторе thread. Видимо первый же запуск им показал что так делать не надо. И что вы думаете? Они ввели специальный мьютекс, который гарантирует что новый поток успеет считать данные из thread_param до того как произойдет выход из конструктора thread. Ректальная офтальмология, короче. Они не оставили интерфейса для передачи потоку своего отдельного параметра. Так что, если не хотите отказываться от boost, то придется делать подобную реализацию, чтобы гарантировать что переменная current_socket не будет переписана до того как новый поток ее прочитает.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

16. "catch для segmentation fault"  
Сообщение от DeadMustdie email(??) on 26-Янв-07, 10:03 
>Нда... Посмотрел я на этот boost и на его реализацию потоков. Редкая
>гадость. Параметр там действительно нельзя передать. В качестве параметра потока (который
>есть во всех нормальных реализациях потоков) они уже используют указатель на
>некий внутренний объект thread_param. Что интересно, объект thread_param они создают как
>локальный в конструкторе thread. Видимо первый же запуск им показал что
>так делать не надо. И что вы думаете? Они ввели специальный
>мьютекс, который гарантирует что новый поток успеет считать данные из thread_param
>до того как произойдет выход из конструктора thread. Ректальная офтальмология, короче.
>Они не оставили интерфейса для передачи потоку своего отдельного параметра. Так
>что, если не хотите отказываться от boost, то придется делать подобную
>реализацию, чтобы гарантировать что переменная current_socket не будет переписана до того
>как новый поток ее прочитает.

Хм... глупости пишете, IMHO.

#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>

struct MyParam
{
  int data_;

  MyParam(const MyParam& mp)
    : data_(mp.data_)
  {}
  MyParam(int data)
    : data_(data)
  {}
};

class MyThread
{
private:
  MyParam mp_;

public:
    MyThread(const MyParam& mp)
      : mp_(mp)
    {}
    void operator()()
    {
        boost::xtime xt;
        boost::xtime_get(&xt, boost::TIME_UTC);
        xt.sec += 10;

        boost::thread::sleep(xt);

        std::cout << "Thread parameter: " << mp_.data_ << std::endl;
    }
};

int main(int argc, char* argv[])
{
    std::cout << "Booting Masa-Dosa..." << std::endl;
    
    MyThread myThread(MyParam(666));
    boost::thread thrd(myThread);
    thrd.join();
    return 0;
}

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

17. "catch для segmentation fault"  
Сообщение от Michelnok (ok) on 26-Янв-07, 15:12 
>
>Хм... глупости пишете, IMHO.

Мобыть... Смотрел бегло.
Раз так, то можно пользоваться и избавиться от глобальной переменной.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

20. "catch для segmentation fault"  
Сообщение от L email(??) on 26-Янв-07, 21:57 
>    MyThread myThread(MyParam(666));
>    boost::thread thrd(myThread);

Интересно, действительно можно от глобальной наконец избавиться.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

14. "catch для segmentation fault"  
Сообщение от Forth (??) on 26-Янв-07, 09:30 
>Я не работал с библиотекой boost. Там что, действительно нельзя передать параметр
>потоку при его создании?
А почему бы не передавать параметр не потоку, а конструктору при создании нового экземпляра Socket?

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

18. "catch для segmentation fault"  
Сообщение от Michelnok (ok) on 26-Янв-07, 15:13 
>А почему бы не передавать параметр не потоку, а конструктору при создании
>нового экземпляра Socket?

Переписывать больше :)

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

19. "catch для segmentation fault"  
Сообщение от L email(??) on 26-Янв-07, 21:37 
>А почему бы не передавать параметр не потоку, а конструктору при создании
>нового экземпляра Socket?
Не совсем понятно. Кроме указателя на Socket никаких других параметров не было необходимости передавать.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

15. "catch для segmentation fault"  
Сообщение от Forth (??) on 26-Янв-07, 09:32 
>Y меня только гипотеза, что в какой-то момент система раз уж отвела
>один и тот же адрес под указатели из разных thread, то
>возможно выдала тот же дескриптор сокета для второй thread, и тогда
>счетчик мог увеличиться на 1.
Таблица дескрипторов на процесс одна и такого быть не может.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

21. "catch для segmentation fault"  
Сообщение от L email(??) on 26-Янв-07, 22:00 
>Таблица дескрипторов на процесс одна и такого быть не может.
Да, с этим уже разобрались, спасибо за man

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Индекс форумов | Темы | Пред. тема | След. тема
Оцените тред (1=ужас, 5=супер)? [ 1 | 2 | 3 | 4 | 5 ] [Рекомендовать для помещения в FAQ]




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру