Memory corruption или просто аномалия
От: lnkuser  
Дата: 13.01.16 20:13
Оценка:
Добрый день!

Наткнулся на аномалию в очень загруженном приложении (перехватываю через libpcap SIP заголовки).
Два потока, все разделено через std::mutex.
(gdb) bt
#0  0x00007ffff74d3f38 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) () from /lib64/libstdc++.so.6
#1  0x0000000000403967 in Call::call_id (this=0x0) at call.cpp:26
#2  0x00000000004047e6 in get_call_by_id (call_id="d3cd1249-34ce-1234-4087-d8cb8a37d12c") at main.cpp:160
...
(gdb) f 2
...
(gdb) l
155     std::shared_ptr<Call> get_call_by_id(const std::string& call_id)
156     {
157         std::lock_guard<std::mutex> lck(call_mtx, std::adopt_lock);
158
159         for (const auto& call: calls) {
160             if (call->call_id() == call_id) {
161                 return call;
162             }
163         }
(gdb) p call->call_id()
$1 = "a8850be9-34cc-1234-4087-d8cb8a37d12c"
(gdb) p call_id
$2 = "d3cd1249-34ce-1234-4087-d8cb8a37d12c"
(gdb) p call
$4 = std::shared_ptr (count 1, weak 0) 0xd6337b8
(gdb) f 1
...
(gdb) l
22      //----------------------------------------------------------------------
23
24      std::string Call::call_id() const
25      {
26          return call_id_;
27      }
28
29      //----------------------------------------------------------------------
(gdb) p this
$3 = (const Call * const) 0x0



Тоесть на фрейме 2 все отлично, а на фрейме 1 уже почему то не объекта Call.
Подозреваю что проблема как-то связана с std::shared_ptr.

Как такое вообще может быть?
Re: Memory corruption или просто аномалия
От: zou  
Дата: 13.01.16 21:43
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Как такое вообще может быть?


Может, gdb ошибочно отображает this=0x0 из-за оптимизированного кода, например? Там чтение NULL в итоге было в этом стеке?
Re[2]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 09:00
Оценка:
Здравствуйте, zou, Вы писали:

zou>Здравствуйте, lnkuser, Вы писали:


L>>Как такое вообще может быть?


zou>Может, gdb ошибочно отображает this=0x0 из-за оптимизированного кода, например? Там чтение NULL в итоге было в этом стеке?



Код не оптимизирован, компилирую так g++ std=c++11 -g -Wall -Wpedantic.
g++ 4.8.2

Там возникали подобные ошибки, в них на одном фрейме this=(корректный адрес), а на последующем уже this=0x0...
Re: Memory corruption или просто аномалия
От: lpd Черногория  
Дата: 14.01.16 10:32
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Тоесть на фрейме 2 все отлично, а на фрейме 1 уже почему то не объекта Call.

L>Подозреваю что проблема как-то связана с std::shared_ptr.

L>Как такое вообще может быть?


Я с shared_ptr много не работал, но если объект shared_ptr в фрейме 2 не NULL, это не значит, что сам объект не NULL. Для проверки shared_ptr на NULL есть специальный operator bool. См. http://ru.cppreference.com/w/cpp/memory/shared_ptr
Похоже на непроинициализированный shared_ptr, которому был вызван только конструктор по умолчанию.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re: Memory corruption или просто аномалия
От: uzhas Ниоткуда  
Дата: 14.01.16 10:53
Оценка: +2
Здравствуйте, lnkuser, Вы писали:

L>157 std::lock_guard<std::mutex> lck(call_mtx, std::adopt_lock);

...
L>Как такое вообще может быть?

вы уверены, что лок захвачен этим потоком в другом месте? если нет, то захватывайте мьютекс так:
std::lock_guard<std::mutex> lck(call_mtx);


дока: http://www.cplusplus.com/reference/mutex/lock_guard/lock_guard/
Re[2]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 14:30
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Здравствуйте, lnkuser, Вы писали:


L>>Тоесть на фрейме 2 все отлично, а на фрейме 1 уже почему то не объекта Call.

L>>Подозреваю что проблема как-то связана с std::shared_ptr.

L>>Как такое вообще может быть?


lpd>Я с shared_ptr много не работал, но если объект shared_ptr в фрейме 2 не NULL, это не значит, что сам объект не NULL. Для проверки shared_ptr на NULL есть специальный operator bool. См. http://ru.cppreference.com/w/cpp/memory/shared_ptr

lpd>Похоже на непроинициализированный shared_ptr, которому был вызван только конструктор по умолчанию.


перед занесением shared_ptr в массив я его проверяю
$4 = std::shared_ptr (count 1, weak 0) 0xd6337b8

вроде как валидный
Re[2]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 14:32
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, lnkuser, Вы писали:


L>>157 std::lock_guard<std::mutex> lck(call_mtx, std::adopt_lock);

U>...
L>>Как такое вообще может быть?

U>вы уверены, что лок захвачен этим потоком в другом месте? если нет, то захватывайте мьютекс так:

U>
U>std::lock_guard<std::mutex> lck(call_mtx);
U>


U>дока: http://www.cplusplus.com/reference/mutex/lock_guard/lock_guard/



Спасибо за ответы, но это тоже не помогает...
Второй поток просто проходит по массиву и проверяет, завершен ли звонок, если да, удаляет элемент (shared_ptr в это случае) из массива.

Пробывал компилировать с clang++, результат такое же...
Re[3]: Memory corruption или просто аномалия
От: lpd Черногория  
Дата: 14.01.16 15:03
Оценка:
Дело в неправильном значении объекта, содержащегося в shared_ptr.
Попробуй создавать не
std::shared_ptr<Call> ptr;

а
std::shared_ptr<Call> ptr(new Call);

Либо, объект уже удален.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Отредактировано 14.01.2016 15:04 lpd . Предыдущая версия .
Re[3]: Memory corruption или просто аномалия
От: B0FEE664  
Дата: 14.01.16 15:17
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>Второй поток просто проходит по массиву и проверяет, завершен ли звонок, если да, удаляет элемент (shared_ptr в это случае) из массива.


Тип calls какой?
И каждый день — без права на ошибку...
Re: Memory corruption или просто аномалия
От: antropolog  
Дата: 14.01.16 15:28
Оценка:
Здравствуйте, lnkuser, Вы писали:

а можно всех посмотреть?
а можно всю ф-цию get_call_by_id увидеть? Непонятно что возвращается если call не найден.
Re[4]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 15:34
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Дело в неправильном значении объекта, содержащегося в shared_ptr.

lpd>Попробуй создавать не
lpd>
lpd>std::shared_ptr<Call> ptr;
lpd>

lpd>а
lpd>
lpd>std::shared_ptr<Call> ptr(new Call);
lpd>

lpd>Либо, объект уже удален.

Создаю через make_shared и проверяю, вроде не преветвуется "naked new"

auto call = std::make_shared<Call>(call_id);
if (call) {
    calls.push_back(call);
}
Re[4]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 15:35
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, lnkuser, Вы писали:


L>>Второй поток просто проходит по массиву и проверяет, завершен ли звонок, если да, удаляет элемент (shared_ptr в это случае) из массива.


BFE>Тип calls какой?



std::vector<std::shared_ptr<Call>> calls;
Re[2]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 15:36
Оценка:
Здравствуйте, antropolog, Вы писали:

A>Здравствуйте, lnkuser, Вы писали:


A>а можно всех посмотреть?

A>а можно всю ф-цию get_call_by_id увидеть? Непонятно что возвращается если call не найден.

std::shared_ptr<Call> get_call_by_id(const std::string& call_id)
{
    std::lock_guard<boost::detail::spinlock> lck(call_mtx, std::adopt_lock);

    for (const auto& call: calls) {
        if (call->call_id() == call_id) {
            return call;
        }
    }

    return nullptr;
}


Незнаю насколько правильно я это все делаю, но при небольшой загрузке приложения все работало. Как только пошел огромный траффик началось такое.
Re[5]: Memory corruption или просто аномалия
От: watchmaker  
Дата: 14.01.16 15:41
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>
L>auto call = std::make_shared<Call>(call_id);
L>if (call) {
L>    calls.push_back(call);
L>}
L>


Это такое неудачное сокращение кода или вставка в вектор действительно происходит без lock?
Re[6]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 15:42
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Здравствуйте, lnkuser, Вы писали:


L>>
L>>auto call = std::make_shared<Call>(call_id);
L>>if (call) {
L>>    calls.push_back(call);
L>>}
L>>


W>Это такое неудачное сокращение кода или вставка в вектор действительно происходит без lock?


нет, конечно там есть лок, я его просто не привел чтобы лишним не захломлять тему
Re[5]: Memory corruption или просто аномалия
От: lpd Черногория  
Дата: 14.01.16 15:45
Оценка:
Если такая ошибка возникает только при большом трафике, то выдвину гипотезу, что удаление(или добавление) звонка плохо синхронизировано и портится память.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[5]: Memory corruption или просто аномалия
От: B0FEE664  
Дата: 14.01.16 15:58
Оценка:
Здравствуйте, lnkuser, Вы писали:

L>>>Второй поток просто проходит по массиву и проверяет, завершен ли звонок, если да, удаляет элемент (shared_ptr в это случае) из массива.

BFE>>Тип calls какой?

L>
L>std::vector<std::shared_ptr<Call>> calls;
L>


Короче. Ставлю диагноз по фотографии. Это не проблемы shared_ptr, это гонки и преждевременная оптимизация.
Мой вам совет: заверните calls в класс, в этом же классе рядом положите защитный мьютекс, сделайте вызовы такие как get_call_by_id(..) методами запирающими этот мьютекс и тогда уж отлаживайте.
И каждый день — без права на ошибку...
Re[6]: Memory corruption или просто аномалия
От: Evgeny.Panasyuk Россия  
Дата: 14.01.16 16:10
Оценка: 7 (2)
Здравствуйте, B0FEE664, Вы писали:

BFE>Мой вам совет: заверните calls в класс, в этом же классе рядом положите защитный мьютекс, сделайте вызовы такие как get_call_by_id(..) методами запирающими этот мьютекс и тогда уж отлаживайте.


Либо взять готовый monitor:
monitor<vector<shared_ptr<Call>>> cs;
// ...
cs([](auto &calls)
{
    // under mutex
});
Отредактировано 14.01.2016 16:10 Evgeny.Panasyuk . Предыдущая версия .
Re[7]: Memory corruption или просто аномалия
От: lnkuser  
Дата: 14.01.16 16:15
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, B0FEE664, Вы писали:


BFE>>Мой вам совет: заверните calls в класс, в этом же классе рядом положите защитный мьютекс, сделайте вызовы такие как get_call_by_id(..) методами запирающими этот мьютекс и тогда уж отлаживайте.


EP>Либо взять готовый monitor:

EP>
EP>monitor<vector<shared_ptr<Call>>> cs;
EP>// ...
EP>cs([](auto &calls)
EP>{
EP>    // under mutex
EP>});
EP>



Большое списибо, почитаю.
Re[7]: Memory corruption или просто аномалия
От: B0FEE664  
Дата: 14.01.16 16:36
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

BFE>>Мой вам совет: заверните calls в класс, в этом же классе рядом положите защитный мьютекс, сделайте вызовы такие как get_call_by_id(..) методами запирающими этот мьютекс и тогда уж отлаживайте.


EP>Либо взять готовый monitor:

EP>
EP>monitor<vector<shared_ptr<Call>>> cs;
EP>// ...
EP>cs([](auto &calls)
EP>{
EP>    // under mutex
EP>});
EP>


Подход интересный (видео посмотрел без звука и не всё), но с monitor я вижу такую проблему: как убедиться, что все операции проводимые с/над calls выполняются исключительно с помощью monitor?
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.