Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> std::string портит память, неправильная работа string 
:(
    Опции темы
Kwal
Дата 25.3.2010, 01:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 25.3.2010

Репутация: нет
Всего: нет



Столкнулся с интересной проблемой. Лет 6 назад использовал одну прогу под ASPLinux 7.2. Исходники компилировались нормально и прога работала (gcc был, по-моему, версии 2.95).
Сейчас появился интерес реанимировать этот проект, но уже под Russian Fedora 12. Компиляция и установка прошли нормально (правда пришлось установить compat-gcc-3.4.2) , но при запуске программа выдала «Segmentation fault».
Исследование проблемы показало, что сбой происходит на , казалось бы, абсолютно нормальном участке кода:

CFilter* f = new CFilter;

Filters.push_back(f); <-------- здесь!

Причем CFilter — некий класс, потомок класса CFilterBase, а Filters является вектором:
class CFilters : public vector<CFilterBase*>. Вроде все нормально.

Поиски корней проблемы привели к следующему. Оказывается, содержимое Filters портится при выполнении следующей команды:

string libfile = dblib_paths[i] + "lib" + DBType + "db.so";

где dblib_paths — vector (количество элементов — 1, i=0), DBType — string, т.е.
std::string DBType;
vector<string> dblib_paths.


Причем происходит следующее. dblib_paths и Filters располагаются в памяти друг за другом.
При выполнении этой строчки происходит пристыковка "/lib" + DBType + "db.so" к dblib_paths непосредственно в месте ее расположения и потом присвоение адреса этой области памяти переменной libfile. Причем пристыковка залезает на область памяти, занимаемой Filters, что впоследствии и приводит к сбою программы.

После выполнения этой строчки libfile располагается там же, где был dblib_paths[0]. Хотя, по логике, при присвоении переменной класса string должно происходить копирование объекта. Т.е. менеджер памяти должен отслеживать ситуацию.

Моделирование данной ситуации на простой программе показало, что действительно, менеджер памяти отслеживает эту ситуацию и при выполнении такой же строчки происходит копирование содержимого dblib_paths в свободную область памяти и там уже происходит пристыковка всего остального. И libfile имеет уже другой адрес, чем dblib_paths.

Вопрос: почему так происходит? Почему раньше (на ASPLinux 7.2) эта прога работала, а теперь, в более новой версии Linux'а — такие косяки? Что-то с реализацией класса string? Или ключи какие надо установить?

Сделал strace -v -olog.txt ./proga.
вот этот самый кусок:


mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78e1000
Здесь я вывожу свойства Filters, который потом портится
write(1, "1.Filters: empty=1 capacity=0 size=0 max_size=1073741823\n", 48) = 48
write(1, "2.Filters: empty=1 capacity=0 size=0 max_size=1073741823\n", 48) = 48
Вот здесь эта строчка :
string libfile = dblib_paths[i] + "/lib" + DBType + "db-" VERSION ".so";

write(1, "3.Filters: empty=0 capacity=-191917709 size=29360180 max_size=1073741823\n", 64) = 64
ВСЁ! Filters испортился!
write(1, " ---> /usr/local/aspseek/lib/libmysqldb-1.2.15.so\n", 50) = 50 <---- вывод содержимого libfile
write(1, "libfile: empty=0 capacity=1073741824 size=43 max_size=1073741820\n", 63) = 63
write(1, "4.Filters:empty=0 capacity=-191917709 size=29360180 max_size=107374182"..., 66) = 66
futex(0xc08068, FUTEX_WAKE_PRIVATE, 2147483647) = 0
open("/usr/local/aspseek/lib/libmysqldb-1.2.15.so", O_RDONLY) = 3

.........
А вот здесь уже происходит обращение Filters.push_baсk(f); Как видно свойства Filters больше не меняются
write(1, "Filters:empty=0 capacity=-191917709 size=29360180 max_size=1073741823\n", 62) = 62
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
write(2, "Address of param: bf802e70\n", 27) = 27
sigreturn() = ? (mask now [])
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV (core dumped) +++
 


P.S. Предвидя вопросы типа где makefile, версия gcc и т.п. скажу, что прога эта - поисковая машина aspseek (www.aspseek.org), там все исходники.
PM MAIL   Вверх
нуп
Дата 25.3.2010, 01:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ботокодер
**


Профиль
Группа: Участник
Сообщений: 987
Регистрация: 22.6.2009
Где: Кременчуг

Репутация: нет
Всего: 33



Код

std::string a = "asdsa" + "1";

Даже такое нельзя написать  smile  А у тебя как то можно и 4 запихнуть
Код

string libfile = dblib_paths[i] + "/lib" + DBType + "db-" VERSION ".so";

PM MAIL   Вверх
Kwal
Дата 25.3.2010, 02:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 25.3.2010

Репутация: нет
Всего: нет



Цитата(нуп @ 25.3.2010,  01:51)
Код

std::string a = "asdsa" + "1";

Даже такое нельзя написать  smile  А у тебя как то можно и 4 запихнуть

А вот так можно:
Код

string str1 ("abc");
string str3 ("123");

string str2 = str1 + "def" + str3 + "smth";


т.к. сначала идет сложение, а потом присвоение.

Добавлено через 1 минуту и 55 секунд
А иначе нафига вообще string нужны  smile 
PM MAIL   Вверх
borisbn
Дата 25.3.2010, 06:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: нет
Всего: 135



1. Абсолютно уверен, что dblib_paths не пустой, и i==0 ?
2. В define VERSION нет знака равенства ?
3. Разбей эту строку на составляющие и выводи Filters после каждого шага


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
maxim1000
Дата 25.3.2010, 09:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: нет
Всего: 110



есть несколько направлений поиска:

1. раз простая программа работает правильно, а сложная неправильно, один из вариантов - постепенно преобразовывать сложную к простой, т.е. удалять код постепенно и смотреть на проявление бага, рано или поздно найдётся изменение, которое "включает/выключает" баг, если не будет понятно почему - удалять всё остальное, пока не будет понятно.

2. если под отладчиком баг воспроизводится - пройтись по этому месту, залезть в исходники string::operator+ и string::operator= и посмотреть, что он там делает не так, при этом лучше (по возможности)

3. проверить, а не удалил/испортил ли кто-то Filters до этого места в программе - в этом случае string может просто рассматривать эту память, как свободную



--------------------
qqq
PM WWW   Вверх
xvr
Дата 25.3.2010, 11:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 20
Всего: 223



90% - проблема в балансе new/delete. Прогони прогу под valgrind


Это сообщение отредактировал(а) xvr - 25.3.2010, 11:32
PM MAIL   Вверх
MAKCim
Дата 25.3.2010, 11:46 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 84
Всего: 207



однозначно компилировать надо с отладочной инфой и прогонять под valgrind'ом
обычно все проблемы с памятью решаются за 5 минут


Цитата(Kwal @  25.3.2010,  01:15 Найти цитируемый пост)
Что-то с реализацией класса string?

скажу по секрету, 99(9)%, что проблема у вас ;)


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Kwal
Дата 25.3.2010, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 25.3.2010

Репутация: нет
Всего: нет



Ошибка найдена!!!   smile 
Как и ожидалось, именно в программе, а не в string  smile 
Причина - в грубом вмешательстве в работу класса string через изменение статического члена класса через дальний указатель. Видимо, это работало под ранними версиями Linux, а впоследствии, может быть,  программная реализация класса слегка изменилась.
Правда пока не совсем понятно,  зачем это надо было делать. Вот что написано в комментах:
Код

    string DBName1;

    // This is just to set reference counter of static member
    // of STL string class to big value
    // so it will never reach 0 in SMP system
    long* ref = (long*)DBName1.data() - 2;
    *ref = 0x40000000;
 

Помог метод приведения программы к простой (метод исключения).
Всем спасибо за советы!!!
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.1598 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.