세그멘테이션 오류

seho·2023년 4월 7일
0

debugging

목록 보기
1/1
post-thumbnail

GPS 데이터를 다루는 개발을 진행하는 중에 세그멘테이션 오류 라는 불친절한 메시지와 함께
개발이 중단되고 큰 혼란에 빠진 상황이었다. 세그멘테이션 오류는 아래와 같은 상황에 발생할 수 있다.

  • 프로그램이 메모리를 잘못 사용할 때 발생
  • 코드와 관련된 메모리 할당 문제
  • 포인터 오류
  • 배열 범위
    내가 겪은 상황은 아래와 같다.

개요

  • C++ 코드 : GPS 및 Gyro 등 UART 통신으로 전달받은 데이터를 Struct 구조체에 담아 보관하고, 라이브러리로 컴파일한다.
  • Python 코드 : C++ 코드와 같은 구조체를 선언하고, 반복문으로 C++ 라이브러리의 함수를 호출하여 구조체에 담긴 데이터를 request.post 요청으로 데이터를 전달한다.

문제 상황

  • Python 코드에서 C++ 라이브러리의 함수를 while문을 통해 계속 요청하는데 5~10분 동안은 데이터가 잘 넘어오는데 무조건 세그멘테이션 오류 라는 불친절한 메시지와 함께 실행이 종료되었다.
  • 디버깅을 하기 위해 C++ 코드에 printf()로 에러가 발생하는 지점을 확인하고 수정해주었다.

문제 해결

  • chatGPT랑 3일간의 토론을 거쳐 어떤 부분에서 오류가 났는지 확인 할 수 있었다.
  1. 기존 코드를 수정해서 사용하는 과정에서 필요없는 파일 쓰기 기능이 있어서 세그멘테이션 오류가 발생했고
  2. 파일 쓰기 부분을 삭제해도 에러가 발생했는데 uart_open 하고 닫지 않아 발생해서 닫는 코드를 추가했다.

기존 코드(C++)

// c++
// 앞부분(데이터 Parsing 등등) 생략
// 아래  process 함수가 Python 코드에서 반복문으로 계속 요청되는 코드이다.
    EXPORT void process(void* st)
    {
        checker = 3;
        unsigned char r_buf[1024];// 여기부터 unsigned char 로 수정
        bzero(r_buf,1024);

        memset(chrBuf, 0x00, 2000);

        fd = uart_open(fd,"/dev/ttyUSB6");/*/dev/ttyUSB 경로 설정 */
        if(fd == -1)
        {
            fprintf(stderr,"uart_open error\n");
            exit(EXIT_FAILURE);
        }

        if(uart_set(fd,BAUD,8,'N',1) == -1)
        {
            fprintf(stderr,"uart set failed!\n");
            exit(EXIT_FAILURE);
        }
		
        // ** 이 부분이 파일을 열어서 해당 데이터를 저장하기 위한 코드인데 삭제해줘야한다. **//
        FILE *fp;
        fp = fopen("Record.txt","w");
        // ** 끝 **//
        
        while(1)
        {
            ret = recv_data(fd,r_buf,44);
            if(ret == -1)
            {
                fprintf(stderr,"uart read failed!\n");
                exit(EXIT_FAILURE);
            }

            for (int i=0;i<ret;i++)
            {
            
            // ** 이 부분 위에서 정의한 파일에 데이터를 기록하는 코드인데 삭제해줘야한다. **//
            fprintf(fp,"%2X ",r_buf[i]);
            // ** 끝 **//
            
            ParseData(r_buf[i]);
            // 1216 체크해서 out
            if(checker == 1){
                checker=0;
                break;
            }
            }
            if(checker == 0){break;}
        }
        // 1216 struct 값 입력 및 반환        
        printf("구조체 전달!\n");
        Struct temp = {yy,mm,dd,hh,mi,ss,ms,ax,ay,az,t,wx,wy,wz,roll,pitch,yaw,mx,my,mz,press,h,lon_final,lat_final,gh,gy,gv,q0,q1,q2,q3,sn,pdop,hdop,vdop};
        *((Struct*)st) = temp;
  • 위 코드는 원래 코드로 세그멘테이션 오류가 발생했다.
  • 중간에 표시한 부분의 파일 쓰기 부분에서 생기는 문제로 계속해서 파일을 써서 발생했다.
  • 또한 마지막에 uart_open에 대한 부분을 제대로 종료해주지 않아서 추가 에러가 발생했다.

수정 코드

    EXPORT void process(void* st)
    {
        try{
            checker = 3;
            unsigned char r_buf[44];// 여기부터 unsigned char 로 수정
            bzero(r_buf,44);
            memset(chrBuf, 0x00, 2000);
            fd = uart_open(fd,"/dev/ttyUSB6");/*/dev/ttyUSB 경로 설정 */

            if(fd == -1)
            {
                fprintf(stderr,"uart_open error\n");
                exit(EXIT_FAILURE);
            }
            if(uart_set(fd,BAUD,8,'N',1) == -1)
            {
                fprintf(stderr,"uart set failed!\n");
                exit(EXIT_FAILURE);
            }

            while(1)
            {
                ret = recv_data(fd,r_buf,sizeof(r_buf));
                if(ret == -1)
                {
                    fprintf(stderr,"uart read failed!\n");
                    exit(EXIT_FAILURE);
                }

                for (int i=0;i<ret;i++)
                {
                    ParseData(r_buf[i]);
                    if(checker == 1){
                        checker=0;
                        break;
                    }
                }
                if(checker == 0){break;}
            }
            // ** uart 를 오픈했으면 닫아줘야한다 **//
            uart_close(fd);
            // ** 끝 **//
            printf("구조체 전달!\n");
            if (st != NULL) { // 추가된 NULL 체크
                Struct temp = { yy, mm, dd, hh, mi, ss, ms, ax, ay, az, t, wx, wy, wz, roll, pitch, yaw, mx, my, mz, press, h, lon_final, lat_final, gh, gy, gv, q0, q1, q2, q3, sn, pdop, hdop, vdop };
                *((Struct*)st) = temp;
            }

        } catch (std::exception& e) {
            std::cerr << "Exception caught: " << e.what() << std::endl;
            exit(1);
        }
    }

마무리

  • while문으로 반복을 돌릴 때 에러가 발생하는 경우가 많다. 미연에 방지하기 위해 디버깅을 잘해줘야한다.
  • uart 같은 통신을 사용할 때 open 했으면 꼭 close 도 꼭 해주자.
  • 에러에 대한 방지를 위해 try,catch,except 등 에러 슈팅을 꼭 처리해주는 습관을 갖자
profile
develop my'self and sw

0개의 댓글