자꾸 발생하는 segmentation
글쓴이: indeok84 / 작성시간: 목, 2009/06/11 - 2:02오후
안녕하세요,
지금 libcap 을 이용해 패킷 캡쳐 프로그램을 만들어 보고 있는 초짜 학생입니다.
헌데 qthread를 이용하기 전에는 segmentation fault가 일어나지 않았었는데 (한번씩 수동으로 돌리다 보니 그렇겠죠;;)
thread로 돌리니 qlistview에 넣기전에 segmentation fault가 자꾸 발생하네요.
어느 부분이 잘못된거 같기는 한데,,, 어느부분인지를 도저히 모르겠네요;;;
소스 좀 봐주실 수 있나요;;
소스 첨부하겠습니다.
고수님분들 도움 부탁드리겠습니다~
written in QT Designer 3
mythread1.h
////////////////////////////////////////////////
#include <stdio.h> #include <stdlib.h> #include <pcap.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <netinet/ip.h> //#include <netinet/if_ether.h> #include <netinet/ether.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> #include <net/ethernet.h> #include <time.h> #include <qmessagebox.h> #include <qlistbox.h> #include <qlistview.h> #include <qstring.h> #include <qthread.h> #include <qtextedit.h> #define MAX_NUM 3 #define TIMEOUT 100 #define PROMISCUOUS 1 #define NONPROMISCUOUS 0 #define SNAPLEN 1024 #define PACKET_ARRAY_SIZE 10000 #define APLISTSIZE 15 //aThread threadA; // object of thread class aThread : public QThread{ public: aThread(); void run(); void stop(); void set_ListBox(QListBox* lb); void set_ListView(QListView* lv, QListViewItem* lvi); void set_TextEdit(QTextEdit* te1, QTextEdit* te2); void set_capturing(void); void set_capturing(QString filterRule); void capturing();//pcap_t *pd,char *dev); void stop_capturing(void); void converter(unsigned char *ch); QString str, str_dinfo; QMessageBox *msg; QListBox* listBox1; QListViewItem* listViewItem1; QListView* listView1; QTextEdit *textEdit1, *textEdit2; protected: struct packetBox{ u_int pkt_len; u_char *pkt; int pcnt; }; struct packetBox pb[100000]; private: volatile bool stopped; char *dev; pcap_t *pd; int cnt; struct bpf_program fp; bpf_u_int32 netp,maskp; char errbuf[PCAP_ERRBUF_SIZE]; }; aThread::aThread(){ int ret; // get net info cnt=0; // packet count stopped = false; // give device name to dev dev = (char*)malloc(sizeof(char)*6); strcpy(dev,"wlan0"); // just do it for compile stage if( (ret = pcap_lookupnet(dev,&netp,&maskp,errbuf)) == -1){ msg = new QMessageBox(); msg->setText("ERROR"); msg->show(); } } void aThread::set_ListBox(QListBox* lb) { listBox1 = lb; } void aThread::set_ListView(QListView* lv, QListViewItem* lvi){ listViewItem1 = lvi; listView1= lv; } void aThread::set_TextEdit(QTextEdit* te1, QTextEdit* te2){ textEdit1 = te1; textEdit2 = te2; } void aThread::run(){ while(!stopped){ capturing();//pd, dev); usleep(100000); } } void aThread::stop(){ stopped = true; } void aThread::stop_capturing(){ pcap_close(pd); } void aThread::set_capturing(){ if(pd){ //stop_capturing(); } usleep(10); pd = pcap_open_live(dev,SNAPLEN, PROMISCUOUS, TIMEOUT, errbuf); } void aThread::set_capturing(QString filterRule){ if(pd){ //stop_capturing(); }usleep(10); pd = pcap_open_live(dev,SNAPLEN, PROMISCUOUS, TIMEOUT, errbuf); if(pcap_compile(pd,&fp, filterRule, 0, netp) == -1){ stop_capturing(); msg = new QMessageBox(); msg->setText("Filter compile error!"); msg->show(); } if(pcap_setfilter(pd,&fp) == -1){ stop_capturing(); msg = new QMessageBox(); msg->setText("set filter error!"); msg->show(); } } void aThread::capturing()//pcap_t *pd,char *dev) { unsigned char *p; struct pcap_pkthdr header; struct ether_header *ep; unsigned short ether_type; struct ip *iph; struct udphdr *udph; struct tcphdr *tcph; struct icmp *icmph; struct arphdr *arph; /////////////////////////////////////////////////// time_t my_time; struct tm *tm_ptr; int len=0;//,temp,chcnt; /////////////////////////////////////////////////// unsigned char *tcpdata, *udpdata, *icmpdata;//, temp_char; QString str_cnt, str_src, str_dst, str_prt, str_time ; QString str_hinfo,sub_info; QString str; str_dinfo.remove(0,str_dinfo.length()); // clear dataString to write at textEdit2 cnt++; // captured packet count time(&my_time); while( (p = (unsigned char*)pcap_next(pd,&header)) == NULL){} tm_ptr = localtime(&my_time); QTextOStream(&str_time) << tm_ptr->tm_hour << ":" <<tm_ptr->tm_min << ":" << tm_ptr->tm_sec; ep = (struct ether_header *)p; p+=sizeof(struct ether_header); ether_type = ntohs(ep->ether_type); if(cnt<10){ QTextOStream(&str_cnt) << 0 << cnt; } else{ QTextOStream(&str_cnt) << cnt; // captured packet count } if(ether_type == ETHERTYPE_IP){ iph = (struct ip*)p; str_src = inet_ntoa(iph->ip_src); // src ip str_dst = inet_ntoa(iph->ip_dst); // dst ip // packet info // QTextOStream(&str_hinfo) << ....; if(iph->ip_p == IPPROTO_TCP){ str_prt = "TCP"; tcph = (struct tcphdr *)(p+iph->ip_hl*4); tcpdata = (unsigned char*)(p+(iph->ip_hl*4)+(tcph->doff*4)); str_hinfo+="\n============ TCP HEADER =============\n"; QTextOStream(&sub_info) << ....; } else if(iph->ip_p == IPPROTO_UDP){ str_prt = "UDP"; udph = (struct udphdr*)(p+iph->ip_hl*4); udpdata = (unsigned char*)(p+iph->ip_hl*4)+8; str_hinfo+="\n============ UDP HEADER =============\n"; QTextOStream(&sub_info) << ....; } else if(iph->ip_p == IPPROTO_ICMP){ str_prt = "ICMP"; icmph = (struct icmp*)(p+iph->ip_hl*4); icmpdata = (unsigned char*)(p+iph->ip_hl*4)+8; str_hinfo+="\n============ ICMP HEADER =============\n"; QTextOStream(&sub_info) << ....; } else if(iph->ip_p == IPPROTO_IGMP){ } } else if(ether_type == ETHERTYPE_ARP){ str_prt = "ARP"; arph = (struct arphdr*)p; // packet info QTextOStream(&str_hinfo) << ....; str_dst = "Broadcast"; str_src = "NO Info"; } else{ str_prt = "NON IP"; str_src = "NON IP"; str_dst = "NON IP"; } listViewItem1 = new QListViewItem(listView1, str_cnt,str_src,str_dst,str_prt,str_time); listView1->insertItem(listViewItem1); pb[cnt-1].pkt = (u_char*)malloc(sizeof(p)); strcpy( (char*)pb[cnt-1].pkt ,(char*)p); if(cnt == 2){ while((unsigned char)len < header.len){ converter(p++); if( (++len%16) == 0){ str_dinfo = str_dinfo.append("\n"); } } textEdit1->setText(str_hinfo+sub_info); textEdit2->setText(str_dinfo); } } void aThread::converter(unsigned char *ch){ unsigned char mask = 0x0f; char val[4]; int i; val[1] = *ch&mask; val[0] = *ch>>4; for(i=0;i<2;i++){ val[i] %= 17; if( val[i]/10 ){ val[i] += 87; } // to start from 97 else{ val[i] += 48; } // to start from 48 }val[i]=' '; val[3]='\0'; str_dinfo = str_dinfo.append(val); }
form1.ui.h
//////////////////////////////////////////
#define PACKET_ARRAY_SIZE 10000 aThread threadA; void form1::init(){ setForm(); setListBox(); called = false; threadA.set_ListView(listView1,lv); threadA.set_TextEdit(textEdit1, textEdit2); } void form1::packetCapture() { threadA.set_capturing(); if( threadA.running() ){ threadA.stop(); }else{ threadA.start(); } }
Forums:
세그먼트 폴트와
세그먼트 폴트와 같이 메모리를 긁는 오류를 잘 잡아내는 것은 디버거만한게 없습니다.
디버거위에서 위 프로그램을 실행해보세요. 그러면 세그먼트 폴트가 발생 할 때 디버거가
그걸 잡아서 어느위치에서 일어났는지 알려줄겁니다.
그럼 그걸 기준으로 만약에 사용자의 함수 안에서 났다면 콜스택을 따라가서 상위 함수에서
뭔가 메모리를 잘못 조작 하는 부분이 있는지 꼼꼼히 따져보세요. 그래도 안보인다면
세그먼트 폴트가 난 위치에서 참조하는 변수들의 내용을 봐보세요. 포인터라면 해당 포인터가
가르키는 정보가 프로그램 구조상 갖을수 있는 값을 가지는지 따져보시고 만약에 가질수 없는
정보라면 그 포인터가 가르키는 정보가 깨지는 시점을 찾아보세요. 그러면 그 시점이 문제점입니다.
포인터가 아니라도 마찬가지입니다. 지역변수라면 콜스택을 따라 올라가면서 지역변수의 범위를
넘어서 데이터를 쓰는 부분이 있는지 확인해보세요. 대부분 잘못된 memset 또는 memcpy 또는 배열의
범위를 넘어서는 인덱스가 문제입니다.
스레드라는 말을 써놓으셨으니 스레드간 동기화 문제일 가능성도 높습니다. 여러개의 스레드에서
동일한 자원(여기서는 메모리)를 "쓰기"를 수행한다면 동기화 객체를 이용하여 보호를 해야합니다.
모든 스레드에서 "읽기"만 수행한다면 동기화 문제는 발생하지 않습니다.
초보라고 하시니 디버거를 아직 쓸줄 모르실지도 모르겠지만 이번 기회에 디버거를 써보세요.
디버거를 써서 문제점을 고민해보셨다면 이미 해결 하셨거나 어느 부분까지 디버깅을 했다는 것을
써 놓으셨을 겁니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
답변
답변 감사합니다.
아직 디버거를 사용해보지 않았는데 디버거로 문제가 발생하는 부분을 찾아봐야겠네요;
그런데 저 프로그램을 보면 함수를 호출해 패킷 내용을 화면에 뿌려주는 말 그대로 "쓰기"를 수행하는데요,
순서대로 쓰기를 수행하는데도 동기화를 수행해야 하나요?(쓰레드는 한개만 돌아갑니다)
그럼 동기화는 필요 없지 않나요?
스레드가 하나라면
스레드가 하나라면 동기화는 필요 없습니다. 동기화가 필요한 것은 같은 자원을
여러 스레드에서 쓰기를 수행할 때 이니까요..
참고로 스레드는 스레드 생성 함수로 만든 것만 스레드가 아닙니다.
프로그램이 맨 처음 실행되면 한개의 스레드가 만들어지고 거기서 main함수가 돌아가게 됩니다.
따라서 만약에 main함수에서도 뭔가 조작하고 생성한 스레드에서도 조작한다면 동기화는 필요합니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
댓글 달기