Вопрос по SegFault

Модератор: Модераторы разделов

Аватара пользователя
Dr.Dkf
Сообщения: 11
ОС: SuSe 10.0, OpenBSD 3.8

Вопрос по SegFault

Сообщение Dr.Dkf »

Прив! Я написал функцию рисования меню с юзаньем ncurses...
Ето функция из menu.c

Код: Выделить всё

WINDOW **draw_menu(int menu_num){
 int i;
 WINDOW **menu;
 menu_s *menues;
menues[0].height = 7;
menues[0].width  = 10;
menues[0].starty = 1;
menues[0].startx = 0;
menues[0].items_num = 5;
menues[0].menu_items [0] = "New";
menues[0].menu_items [1] = "Open";
menues[0].menu_items [2] = "Save";
menues[0].menu_items [3] = "--------";
menues[0].menu_items [4] = "Exit";
menues[1].height = 12;
menues[1].width  = 10;
menues[1].starty = 1;
menues[1].startx = 5;
menues[1].items_num = 10;
menues[1].menu_items [0] = "Undo";
menues[1].menu_items [1] = "Redo";
menues[1].menu_items [2] = "--------";
menues[1].menu_items [3] = "Cut";
menues[1].menu_items [4] = "Copy";
menues[1].menu_items [5] = "Paste";
menues[1].menu_items [6] = "Delete";
menues[1].menu_items [7] = "--------";
menues[1].menu_items [8]= "Search";
menues[1].menu_items [9]= "Replace";
menues[2].height = 4;
menues[2].width = 15;
menues[2].starty = 1;
menues[2].startx = 10;
menues[2].items_num = 2;
menues[2].menu_items [0] = "Run";
menues[2].menu_items [1] = "Spellcheck";
 menu=(WINDOW **)malloc((menues[menu_num].items_num+4)*sizeof(WINDOW *));
 move(menues[menu_num].starty,menues[menu_num].startx);
 menu[0] = newwin(menues[menu_num].height,menues[menu_num].width,menues[menu_num].starty,menues[menu_num].startx);
 wbkgd(menu[0],COLOR_PAIR(1));
 box(menu[0],ACS_VLINE,ACS_HLINE);

 for (i=1;i<menues[menu_num].items_num+1;i++) {
  menu[i]=subwin(menu[0],1,menues[menu_num].width-2,menues[menu_num].starty+i,menues[menu_num].startx+1);
 }
 for (i=1;i<menues[menu_num].items_num+1;i++) {
  wprintw(menu[i],menues[menu_num].menu_items [i-1],i);
 }
 wbkgd(menu[1],COLOR_PAIR(2));
 for (i=2;i<menues[menu_num].items_num+1;i++) {
  wbkgd(menu[i],COLOR_PAIR(0));
 }
 wbkgd(menu[5],COLOR_PAIR(0));
 wrefresh(menu[0]);
 return menu;
}

А здесь определен тип menu_s или _menu_struct из menu.h

Код: Выделить всё

typedef struct _menu_struct {
 char *menu_items[20];
 int items_num;
 int height;
 int width;
 int starty;
 int startx;
} menu_s;

..В етой функции(gdb так сказал) прога выдает segfault....а я не врубаюсь почему... может с указателями чет напортачил... Кароч, может ктонить сказать в чем здесь ошибка? Или подскажите как заюзать gdb или ченить другое чтобы найти самому ошибку...
"You Face To Face
With Man Who Sold The World"


Nirvana - The Man Who Sold The World
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Вопрос по SegFault

Сообщение v04bvs »

menu_s *menues;

Так, объявили переменную menues, которая есть указатель на тип menu_s. Соответственно в этом указателе сейчас мусор, т.е. он указывает на какую-то случайную область памяти


menues[0].height = 7;

И теперь мы эту случайную область разыменовываем и записываем туда данные. Segmentation fault это лучшее, что могло произойти, тебе просто повезло :)

Кстати gdb обычно указывает номер строчки, в которой всё упало. Есть там такая команда backtrace
Спасибо сказали:
Аватара пользователя
halturin
Сообщения: 167
ОС: Linux

Re: Вопрос по SegFault

Сообщение halturin »

в юзерспейсе страшнее сегфолта ничего произойти не может в принципе.
Спасибо сказали:
Аватара пользователя
Skladnoy
Сообщения: 90
ОС: Debian

Re: Вопрос по SegFault

Сообщение Skladnoy »

Может. Можно данные какие-нибудь перезаписать, или даже код. И как себя поведет программа, и где вывалится, и что при этом будет не известно никому. Были прецеденты..
Спасибо сказали:
Аватара пользователя
halturin
Сообщения: 167
ОС: Linux

Re: Вопрос по SegFault

Сообщение halturin »

а можно поподробнее...? каким макаром программа из собственного адресного пространство может повлиять на что-то другое? в линухе первый гиг адресного пространства зарезервирован ядром, остальные 3 отданы пользовательской программе. собсно сегфолт и происходит когда программа пытается обратиться по адресу 1-го гига. акромя своего кода в памяти она нифига испортить не может.
Спасибо сказали:
Аватара пользователя
Skladnoy
Сообщения: 90
ОС: Debian

Re: Вопрос по SegFault

Сообщение Skladnoy »

Именно свой код и именно свои данные может испортить. Полезет в чужие - будет сегфолт. Куда хуже если полезет в свои. Тогда не известно, когда и как вывалится. Buffer overflow & arbitrary code execution в принципе растут именно оттуда.

Хотя неинициализированные указатели обычно указывают в черт знает куда...
Спасибо сказали:
Аватара пользователя
Dr.Dkf
Сообщения: 11
ОС: SuSe 10.0, OpenBSD 3.8

Re: Вопрос по SegFault

Сообщение Dr.Dkf »

Возникла фигня....

Код: Выделить всё

main.c: In function ‘WINDOW** draw_menu(int)’:
main.c:19: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:20: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:21: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:22: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:23: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:24: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:25: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:26: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:27: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:28: error: no match for ‘operator[]’ in ‘menues[0]’
main.c:29: error: no match for ‘operator[]’ in ‘menues[1]’
main.c:30: error: no match for ‘operator[]’ in ‘menues[1]’
main.c:31: error: no match for ‘operator[]’ in ‘menues[1]’
main.c:32: error: no match for ‘operator[]’ in ‘menues[1]’
main.c:33: error: no match for ‘operator[]’ in ‘menues[1]’
main.c:34: error: no match for ‘operator[]’ in ‘menues[1]’
... итд итп...

сам не знаю откуда такое мб...
"You Face To Face
With Man Who Sold The World"


Nirvana - The Man Who Sold The World
Спасибо сказали:
Аватара пользователя
halturin
Сообщения: 167
ОС: Linux

Re: Вопрос по SegFault

Сообщение halturin »

я так полагаю то что ты сейчас компилишь не есть то что ты показал нам в начале топика.
будь добр, засвети.
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Вопрос по SegFault

Сообщение v04bvs »

halturin писал(а): ↑
08.01.2007 16:34
в юзерспейсе страшнее сегфолта ничего произойти не может в принципе.

Код: Выделить всё

void a()
{
    b();
}

void b()
{
    c();
}

void c()
{
    int a;
    int *p = &a;
    while (*p++ = 1)
    ;
}


int main(int argc, char *argv[])
{
    a();
}

Вот этот код отладьте :) Тут только valgrind поможет. Самое страшное это когда портится куча, и программа сходит с ума.
Страшно для программиста конечно.
Спасибо сказали:
Аватара пользователя
Dr.Dkf
Сообщения: 11
ОС: SuSe 10.0, OpenBSD 3.8

Re: Вопрос по SegFault

Сообщение Dr.Dkf »

От он...файл...

Код: Выделить всё

#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#define
/* KEYS */
#define ENTER 10
#define ESCAPE 27
#define KEY_CF 6
#define KEY_CE 5
#define KEY_CH 8
#define KEY_CR 18
#define KEY_TAB 9
#include "pd_types.h"
#include "peditor.h"
WINDOW **draw_menu(int menu_num){
 int i;
 WINDOW **menu;
 menu_s menues;
menues[0].height = 7;
menues[0].width  = 10;
menues[0].starty = 1;
menues[0].startx = 0;
menues[0].items_num = 5;
menues[0].menu_items [0] = "New";
menues[0].menu_items [1] = "Open";
menues[0].menu_items [2] = "Save";
menues[0].menu_items [3] = "--------";
menues[0].menu_items [4] = "Exit";
menues[1].height = 12;
menues[1].width  = 10;
menues[1].starty = 1;
menues[1].startx = 5;
menues[1].items_num = 10;
menues[1].menu_items [0] = "Undo";
menues[1].menu_items [1] = "Redo";
menues[1].menu_items [2] = "--------";
menues[1].menu_items [3] = "Cut";
menues[1].menu_items [4] = "Copy";
menues[1].menu_items [5] = "Paste";
menues[1].menu_items [6] = "Delete";
menues[1].menu_items [7] = "--------";
menues[1].menu_items [8]= "Search";
menues[1].menu_items [9]= "Replace";
menues[2].height = 4;
menues[2].width = 15;
menues[2].starty = 1;
menues[2].startx = 10;
menues[2].items_num = 2;
menues[2].menu_items [0] = "Run";
menues[2].menu_items [1] = "Spellcheck";
 menu=(WINDOW **)malloc((menues[menu_num].items_num+4)*sizeof(WINDOW *));
 move(menues[menu_num].starty,menues[menu_num].startx);
 menu[0] = newwin(menues[menu_num].height,menues[menu_num].width,menues[menu_num].starty,menues[menu_num].startx);
 wbkgd(menu[0],COLOR_PAIR(1));
 box(menu[0],ACS_VLINE,ACS_HLINE);

 for (i=1;i<menues[menu_num].items_num+1;i++) {
  menu[i]=subwin(menu[0],1,menues[menu_num].width-2,menues[menu_num].starty+i,menues[menu_num].startx+1);
 }
 for (i=1;i<menues[menu_num].items_num+1;i++) {
  wprintw(menu[i],menues[menu_num].menu_items [i-1],i);
 }
 wbkgd(menu[1],COLOR_PAIR(2));
 for (i=2;i<menues[menu_num].items_num+1;i++) {
  wbkgd(menu[i],COLOR_PAIR(0));
 }
 wbkgd(menu[5],COLOR_PAIR(0));
 wrefresh(menu[0]);
 return menu;
}

int scroll_menu(WINDOW **items,int count)
{
 int key;
 int selected=0;
 while (1) {
  key=getch();
  if (key==KEY_DOWN || key==KEY_UP) {
   wbkgd(items[selected+1],COLOR_PAIR(0));
   wnoutrefresh(items[selected+1]);
   if (key==KEY_DOWN) {
    selected=(selected+1) % count;
   }
   else {
    selected=(selected+count-1) % count;
   }
   wbkgd(items[selected+1],COLOR_PAIR(2));
   wnoutrefresh(items[selected+1]);
   doupdate();
  }
  else if (key==ESCAPE) {
   return -1;
  }
  else if (key==ENTER) {
   return selected;
  }
 }
}

sel_s OnKeyDown(WINDOW **menu) {
 int i,j,selected;
 char keys[] = {KEY_CF,KEY_CE,KEY_CR,KEY_CH};
 int menues[] = {0,1,2,3};
 int items[] = {5,10,2,0};
 char key;
 sel_s sel;

 i=0;
 do {
 key = getch();
  for (j=0;j<4;j++) {
   if (key == keys [j]){
    menu = draw_menu(j);
    selected = scroll_menu(menu,items[j]);
    move(8,1);
    printw("%d",menues[j],"\n");
    printw("%d",(selected+1));
    sel.menu=menues[j];
    sel.item=selected;
    sel.flag=1;
    return sel;
   }
  }
  if (key == ESCAPE) {
   refresh();
   endwin();
   sel.flag = 0;
   return sel;
  }
 } while(i=0);
 sel.flag=0;
 return sel;
}

void draw_menubar(WINDOW *mb){
 curs_set(0);
 char *menues[] = {"File","Edit","Run","Help"};
 int i,j,next_pos;
 next_pos=0;
 for (i=0;i<4;i++) {
  wattron(mb,COLOR_PAIR(1));
  wprintw(mb,"%c", menues [i][0]);
  wattroff(mb,COLOR_PAIR(1));
  wattron(mb,COLOR_PAIR(0));
  for (j=1;j<strlen(menues [i]); j++) {
   wprintw(mb,"%c",menues [i][j]);
  }
  wattroff(mb,COLOR_PAIR(0));
  next_pos = next_pos + strlen(menues [i])+1;
  wmove(mb,0,next_pos);
 }
}

int main(int argc, char  *argv[]) {
 init_ncurses();

 WINDOW *menubar, **menu;
 int height,width;
 sel_s sel;

 getmaxyx(stdscr,height,width);
 menubar = subwin(stdscr,1,width,0,0);
 draw_menubar(menubar);
 refresh();
 do {
  sel = OnKeyDown(menu);
 } while(sel.flag!=0);
 getch();
 endwin();
 return 0;
}
"You Face To Face
With Man Who Sold The World"


Nirvana - The Man Who Sold The World
Спасибо сказали:
Аватара пользователя
halturin
Сообщения: 167
ОС: Linux

Re: Вопрос по SegFault

Сообщение halturin »

while (*p++ = 1)

а не ==?
если да, то не вижу практического применения => patch(brain);
Спасибо сказали:
Аватара пользователя
Dr.Dkf
Сообщения: 11
ОС: SuSe 10.0, OpenBSD 3.8

Re: Вопрос по SegFault

Сообщение Dr.Dkf »

Усе заработало!!!!!!!!! СЕНКС ВАМ ЛЮДИ!!!
"You Face To Face
With Man Who Sold The World"


Nirvana - The Man Who Sold The World
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Вопрос по SegFault

Сообщение v04bvs »

halturin писал(а): ↑
08.01.2007 19:49
while (*p++ = 1)

а не ==?
если да, то не вижу практического применения => patch(brain);

Не ==
Это просто пример того, что бывает, когда стек портится. Нет ни backtrace, ни отладочной информации, вообще ничего, только факт крэша. Естественно в реальной жизни стек портится не так,банальные переполнения буфера
char s[16];
и тд.

Ну ладно, это оффтопик уже.
Спасибо сказали:
Аватара пользователя
aLexx programmer
Сообщения: 985
Статус: Турук-Макто
ОС: Gentoo -> Ubuntu

Re: Вопрос по SegFault

Сообщение aLexx programmer »

(v04bvs @ Jan 9 2007, в 01:45) писал(а):Нет ни backtrace, ни отладочной информации, вообще ничего, только факт крэша.

Немного не понял... gdb выдал и номер строки, и значения переменных после sigsegv.
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Вопрос по SegFault

Сообщение v04bvs »

aLexx programmer писал(а): ↑
09.01.2007 14:56
(v04bvs @ Jan 9 2007, в 01:45) писал(а):
Нет ни backtrace, ни отладочной информации, вообще ничего, только факт крэша.

Немного не понял... gdb выдал и номер строки, и значения переменных после sigsegv.

Ух ты. Сейчас линукса нет, сорри. студия 2005 ничего не выдала :)
респект gdb :) Надо будет покопать :)
Спасибо сказали:
Аватара пользователя
halturin
Сообщения: 167
ОС: Linux

Re: Вопрос по SegFault

Сообщение halturin »

вот и я, пользуя gdb так и не въехал, что же может быть страшнее сегфолта... если где и забудешь выделить память, то рано или поздно сегфолт обеспечен. а gdb тебе поможет выловить. волгринд больше для утечек памяти, а не необорот - c ее невыделением :)
Спасибо сказали:
Аватара пользователя
aLexx programmer
Сообщения: 985
Статус: Турук-Макто
ОС: Gentoo -> Ubuntu

Re: Вопрос по SegFault

Сообщение aLexx programmer »

(halturin @ Jan 10 2007, в 22:31) писал(а):вот и я, пользуя gdb так и не въехал, что же может быть страшнее сегфолта... если где и забудешь выделить память, то рано или поздно сегфолт обеспечен.

Поломать свои же данные --- страшнее сегфолта. Ибо очень-очень трудно отловить то место, где всё портится.
Спасибо сказали:
Аватара пользователя
Ballantre
Сообщения: 114
ОС: Linux

Re: Вопрос по SegFault

Сообщение Ballantre »

Честно говоря, поломать собственные данные получилось, только когда пришлось дизассемблирование писать на асме. А вот ни на С, ни на С++, ни на чем другом не удалось.
P.S. Как ни старался.
Я двадцать лет знал его и всегда ненавидел, и всегда восхищался, и всегда по-рабски боялся его.
Спасибо сказали:
Аватара пользователя
aLexx programmer
Сообщения: 985
Статус: Турук-Макто
ОС: Gentoo -> Ubuntu

Re: Вопрос по SegFault

Сообщение aLexx programmer »

(Ballantre @ Jan 11 2007, в 13:21) писал(а):А вот ни на С, ни на С++, ни на чем другом не удалось.
P.S. Как ни старался.

Плохо старался ;)
Спасибо сказали:
ToniX
Сообщения: 11

Re: Вопрос по SegFault

Сообщение ToniX »

Ballantre писал(а): ↑
11.01.2007 13:24
Честно говоря, поломать собственные данные получилось, только когда пришлось дизассемблирование писать на асме. А вот ни на С, ни на С++, ни на чем другом не удалось.
P.S. Как ни старался.

Ну это как раз проще простого:

Код: Выделить всё

#include <iostream>

const size_t SIZE = 4;

struct Some {
  unsigned char arr[SIZE];
  unsigned val;
};

int main()
{
  Some s;
  s.val = 0;

  std::cout << "s.val == " << s.val << std::endl;
  s.arr[SIZE + 3] = 5;
  std::cout << "s.val == " << s.val << std::endl;

  return 0;
}


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

P.S.
Я был свидетелем случая, когда при считывании строки размер буфера указывался неправильно (в большую сторону). При этом булевский флаг, объявленный следом за буфером, затерался, изменяясь с единицы на ноль. И из-за этого вся программа работала неправильно. А если бы вместо простого флага (состояние которого легко отследить в отладчике) был бы объект класса, скажем, std::list? Все было бы гораздо веселее...
Спасибо сказали:
Аватара пользователя
halturin
Сообщения: 167
ОС: Linux

Re: Вопрос по SegFault

Сообщение halturin »

по сути, твой s.arr[SIZE + 3] = 5; мало чем отличается от записи в неаллоцируемую область типа
int *a; *a=5; просто замаскировано чуток больше. главное в разработке - аккуратность и внимательность.
пренебрегая этими двумя важными составляющими на выходе и получаются ляпы.

ToniX писал(а): ↑
11.01.2007 15:03
Я был свидетелем случая, когда при считывании строки размер буфера указывался неправильно (в большую сторону). При этом булевский флаг, объявленный следом за буфером, затирался...

не понял... строка была больше буфера или наоборот, еже ли последнее - то что-то ты друг мой не то говоришь. ну а если все-таки буфер был недостаточен, то это нормально что булева переменная переписывалась ) ибо переполнение шло ) только вот боюсь там не только булева перетиралась, еще n-байт следом за ней )
Спасибо сказали:
Аватара пользователя
elide
Бывший модератор
Сообщения: 2421
Статус: Übermensch
ОС: лялих

Re: Вопрос по SegFault

Сообщение elide »

это нормально что булева переменная переписывалась

а никто и не говорит, что это не нормально... тебе говорят, что это страшнее чем SIGSEGV. при SIGSEGV программа просто падает. известно где и известно когда. это скучно.
а вот когда у тебя портятся твои данные, особенно в многопоточном приложении, то ничего никуда не падает... программа тихо глючит, а ты несколько часов не можешь понять почему. тебе кажется, что это менее страшная ситуация?
слава роботам!
Спасибо сказали:
ToniX
Сообщения: 11

Re: Вопрос по SegFault

Сообщение ToniX »

по сути, твой s.arr[SIZE + 3] = 5; мало чем отличается от записи в неаллоцируемую область типа int *a; *a=5; просто замаскировано чуток больше.

Отличается, и очень здорово:
sizeof( Some ) >= SIZE*sizeof( unsigned char ) + sizeof( unsigned );
Следовательно, s.arr[SIZE + 3] попадет в область памяти, занимаемую переменной s (если конечно sizeof( unsigned char) == 1 && sizeof( unsigned ) == 4). А эта память существует и никакого "SegFault" не будет. Ошибка проявится при использовании s.val. А где и когда это произойдет (может на клиентской стороне за несколько тысяч км от сервера) никто не знает.
главное в разработке - аккуратность и внимательность.
пренебрегая этими двумя важными составляющими на выходе и получаются ляпы.

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

Сторка была больше буфера.
Там было что-то типа...

Код: Выделить всё

char str[MAX_LEN];
unsigned flag = 1;

ReadStr(str, /*что-то > MAX_LEN*/);

// ...

if( flag ) {
  // ...
}

Хитрость в том, что завершающий ноль строки очень "удачно" попал на первый байт flag, тем самым обнулив его. Была бы строка на 1 байт короче/длиннее и ошибка бы не проявилась сразу, когда ее легко можно было исправить.
то это нормально что булева переменная переписывалась ) ибо переполнение шло )

Да, нормально. И что?
Еще раз приведу цитату Ballantre, которую я комментировал:
Честно говоря, поломать собственные данные получилось, только когда пришлось дизассемблирование писать на асме. А вот ни на С, ни на С++, ни на чем другом не удалось.
P.S. Как ни старался.
Спасибо сказали:
Аватара пользователя
Ballantre
Сообщения: 114
ОС: Linux

Re: Вопрос по SegFault

Сообщение Ballantre »

ToniX , просто я не совсем верно понял суть ошибок. А такие действительно часто могут возникнуть.
Я двадцать лет знал его и всегда ненавидел, и всегда восхищался, и всегда по-рабски боялся его.
Спасибо сказали:
Аватара пользователя
halturin
Сообщения: 167
ОС: Linux

Re: Вопрос по SegFault

Сообщение halturin »

ToniX писал(а): ↑
11.01.2007 21:04
Отличается, и очень здорово:

физика переполнения мне известна и я прекрасно понимаю о чем ты говоришь.
когда я писал про "неалоцированную память" в твоем случае эта область аллоцирована, но не для буфера, в моем примере просто запись будет не в область следом за переменной а бог знает куда, ну ежели повезет и звезды выстроятся в нужной последовательности, то возможно и запишет в ячейку следом за переменной int *a :)

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