반응형

테스트 기기: 엔스퍼트 아이덴티티탭 (E201V)

안드로이드 버전: 이클레어(Eclair, 2.1), 프로요(Froyo, 2.2)



연구실에서 개발한 테스트용 앱을 아이덴티티탭(안드로이드 2.1)에 설치하려고 했는데 "응용프로그램이 설치되지 않았습니다."라는 메세지와 함께 아래와 같은 설치 실패 화면만 보게 되었다.


(그림 1) 아이덴티티탭에 설치되지 않는 프로그램



예전 개발환경에서는 (이클립스 + 안드로이드 sdk 수동설치) 문제없이 설치가 되었는데, 최근에 ADT (Android Developer Tools)에서 같은 코드로 프로젝트를 만들고 설치를 시도하니 안된다. Apk 파일만 SD카드에 따로 복사해서 "알 수 없는 소스" 옵션을 체크하고 설치를 시도해도 되지 않았다.

혹시 안드로이드 버전이 너무 낮아서 그런가 해서 아이덴티티탭을 프로요(2.2)로 펌웨어 업데이트를 했는데도 문제는 해결되지 않았다.



*해결의 실마리 (?)

예전 개발환경에 있던 프로젝트와 ADT에 있는 프로젝트의 차이점이 하나 있었는데, 참조하는 라이브러리 jar 파일의 위치였다.

예전 개발환경 (이클립스 + 안드로이드 sdk 수동설치)에서는 프로젝트 밑에 아무 폴더를 만들고(예: lib), 그 안에 jar 파일을 집어넣었다. 그리고 이클립스의 Java Build Path에서 해당 jar 파일을 참조하도록 선택했다.


반면에 ADT를 비롯해서 비교적 최신 버전의 안드로이드 개발환경(이클립스 플러그인)에서는 프로젝트 밑에 "libs" 폴더를 만들고, 그 안에 jar 파일을 복사해 넣으면 자동으로 참조가 된다.


(그림 2) ADT에서 안드로이드 프로젝트의 libs 폴더에 jar 파일을 추가하는 경우


그런데 문제는, 안드로이드 2.1 프로젝트에 대해서 이렇게 libs 폴더를 통해서 jar 파일을 추가해도 프로젝트 설정(Project Properties)에서는 보이지 않는 것이다.


(그림 3) 이상하게 libs에서 추가한 jar 파일 2개가 표시되지 않는다.



그래서 ADT에서도 다시 예전 방식대로 참조해 보았다. libs 대신 그냥 일반적인 폴더(이 예제에서는 lib)를 만들고, 그 안에 jar 파일을 추가하고,


(그림 4) libs 폴더 대신 lib 폴더 사용. 자동으로 jar 파일을 참조하지 않는다.


프로젝트 설정에서 수동으로 jar 파일을 아래 그림 5~그림 6과 같이 추가했다.


(그림 5) "Add JARs..." 버튼을 눌러서 수동으로 추가


(그림 6) 해당 프로젝트의 lib 폴더 밑에 있는 jar 파일을 복수 선택



그리고 Java Build Path 창에서 "Order and Export" 탭으로 가서, 체크되어 있지 않은 2개의 참조된 라이브러리를 체크해 주었다.


(그림 7) Order and Export 탭에서 참조 라이브러리를 체크한다.


위와 같이 설정한 뒤에 프로젝트를 새로 빌드하고 나서 설치를 시도해 보니, 아이덴티티탭에 문제없이 설치가 되었다.



(주의)

이 방법은 오히려 최신 버전의 안드로이드 버전에서는(경험상으로 4.0 이상) 오히려 앱 빌드가 안되는 문제를 초래할 수도 있다. 최신 버전의 안드로이드 플랫폼에서 개발할 때는 libs 폴더에 jar 파일을 추가해서 자동으로 참조되도록 하는 것이 좋다. 또한 jar 파일이 아니고 Projects 탭에 바로 프로젝트를 참조하는 것도 문제를 일으킬 소지가 크다.




반응형
블로그 이미지

Bryan_

,
반응형


C언어로 작성된 라우팅 프로토콜에서, 디버그를 목적으로 라우팅 테이블을 문자열(char* )로 출력하도록 했는데, 어느 순간 아래와 같은 buffer overflow 메세지와 함께 프로세스가 중단되었다.


18:58:47.109 AodvUseraLogRtTable: 

        dest            next     dst_seq  ifidx  #nextHops

----------------------------------------------------------------    (여기까지 문자열을 출력하는 중이었음)

*** buffer overflow detected ***: ./aodvd terminated

======= Backtrace: =========

/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x50)[0x1f5df0]

/lib/i386-linux-gnu/libc.so.6(+0xe4cca)[0x1f4cca]

/lib/i386-linux-gnu/libc.so.6(+0xe43c8)[0x1f43c8]

/lib/i386-linux-gnu/libc.so.6(_IO_default_xsputn+0x95)[0x1797e5]

/lib/i386-linux-gnu/libc.so.6(_IO_vfprintf+0x2b06)[0x14fc66]

/lib/i386-linux-gnu/libc.so.6(__vsprintf_chk+0xad)[0x1f447d]

./aodvd[0x804c395]

./aodvd[0x805228a]

./aodvd[0x80596a1]

./aodvd[0x804dff8]

./aodvd[0x804e3ab]

./aodvd[0x804b179]

/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x126e37]

./aodvd[0x80490d1]

======= Memory map: ========

00110000-0026a000 r-xp 00000000 08:01 1570625    /lib/i386-linux-gnu/libc-2.13.so

0026a000-0026b000 ---p 0015a000 08:01 1570625    /lib/i386-linux-gnu/libc-2.13.so

0026b000-0026d000 r--p 0015a000 08:01 1570625    /lib/i386-linux-gnu/libc-2.13.so

0026d000-0026e000 rw-p 0015c000 08:01 1570625    /lib/i386-linux-gnu/libc-2.13.so

0026e000-00271000 rw-p 00000000 00:00 0 

00271000-0028b000 r-xp 00000000 08:01 1570653    /lib/i386-linux-gnu/libgcc_s.so.1

0028b000-0028c000 r--p 00019000 08:01 1570653    /lib/i386-linux-gnu/libgcc_s.so.1

0028c000-0028d000 rw-p 0001a000 08:01 1570653    /lib/i386-linux-gnu/libgcc_s.so.1

004df000-004fb000 r-xp 00000000 08:01 1570612    /lib/i386-linux-gnu/ld-2.13.so

004fb000-004fc000 r--p 0001b000 08:01 1570612    /lib/i386-linux-gnu/ld-2.13.so

004fc000-004fd000 rw-p 0001c000 08:01 1570612    /lib/i386-linux-gnu/ld-2.13.so

00661000-00662000 r-xp 00000000 00:00 0          [vdso]

08048000-0805e000 r-xp 00000000 08:01 1190565    /home/shan/exp/routing/aodv-uu-usera/aodvd

0805e000-0805f000 r--p 00015000 08:01 1190565    /home/shan/exp/routing/aodv-uu-usera/aodvd

0805f000-08060000 rw-p 00016000 08:01 1190565    /home/shan/exp/routing/aodv-uu-usera/aodvd

08060000-08061000 rw-p 00000000 00:00 0 

09aec000-09b0d000 rw-p 00000000 00:00 0          [heap]

b7846000-b7847000 rw-p 00000000 00:00 0 

b7856000-b7859000 rw-p 00000000 00:00 0 

bfe42000-bfe63000 rw-p 00000000 00:00 0          [stack]

$

--> 내용 수정
  다시 확인한 결과, 위의 출력 결과는 strcat에서 buffer overflow가 발생하기 전에, 다른 debug 함수에서 sprintf 함수에 쓰이는 문자열 버퍼의 크기가 제한되어 있어서 발생한 것이며, strcat으로 인한 출력 결과가 아니었다. 하지만 strcat을 수행할 경우에도 이와 비슷한 형태의 에러가 출력되므로, 단지 형태를 참고하는 정도로만 확인하면 좋겠다.


문제가 발생한 해당 함수(AodvUseraLogRtTable이라는 개인적으로 만든 함수)에서는 strcat을 쓰고 있었고, 정해진 크기의 문자열에 for문으로 임의의 갯수만큼 다른 문자열을 한 줄씩 추가하는 형태였다.

char buf[2000] = {0};


for ( i = 0 ; i < RT_TABLESIZE ; i++ )

{

    char* temp = ~~~~~~~~~~; // temp에 자동으로 입력되는 문자열

    strcat ( buf, temp );

}


라우팅 테이블에 4줄까지는 괜찮다가 5줄짜리를 출력할 때 문제가 생긴 것으로 보면 한 줄에 대략 200바이트 내외의 길이가 추가되면서 buf의 크기를 넘어서면서 문제가 생겼을 것이다. 이런 접근을 허용하게 되면, heap 영역에서 프로세스마다(또는 변수마다) 활용하는 메모리 영역을 넘어서는 부분을 수정하게 되므로, 다른 프로세스(또는 다른 변수)에서 예상치 못한 결과를 얻게 되는 문제가 있다.




C언어에서 다양한 방법이 가능하겠지만, 가장 간단하게는 두 가지의 해결 방향이 있을 것 같다.


(1) temp의 사이즈를 미리 지정하고, if문을 이용해서 붙이는 대상(buf)의 크기를 넘어가지 않도록 제어하기

  위의 경우에는 temp* 문자열의 크기가 어떻게 되는지 알 수 없다. 문자열을 생성하는 코드에 따라서 아주 길 수도 이쏙 짧을 수도 있다. 아예 처음부터 temp 문자열을 일정한 크기로 만들고, 형태(format)를 잘 정의해서 규모 있게 운용하면 예상 외의 buffer overflow는 줄일 수 있을 것이다.

char buf[2000] = {0};

char temp[100] = {0}; // temp의 크기를 강제 지정

int buf_pos = 0;


for ( i = 0 ; i < RT_TABLESIZE ; i++ )

{

    memset( temp, 0, 100);

    sprintf( temp, "~~~~~~", ... ); // temp에 입력시 format을 미리 정해서 크기를 일정하게

    if( buf_pos + 100 < 2000 )

    {

        // buf에 여유 공간이 있을 때만 strcat 수행

        strcat ( buf, temp ); 

        buf_pos += 100;

    }

}



(2) strncat을 이용해서 temp의 맨 처음으로부터 일정 크기의 문자열만 붙이기 (+ if문 활용해서 buf 크기 넘어가지 않도록 제어)

  temp 문자열의 크기를 미리 정할 수 없지만 앞의 일부분만 가져다 쓰면 되는 경우에는, strncat 함수를 이용해서 붙여넣을 temp 문자열 중에서 정해진 크기만큼만 buf에 붙여지도록 지정할 수 있다.

만약 100바이트씩만 붙인다면, " strncat ( buf, temp, 100); "이 될 것이다.

char buf[2000] = {0};

int buf_pos = 0;


for ( i = 0 ; i < RT_TABLESIZE ; i++ )

{

    char* temp = ~~~~~~~~~~; // temp에 자동으로 입력되는 문자열

    if( buf_pos + 100 < 2000 )

    {

        strncat ( buf, temp, 100 ); // temp의 맨 앞에서부터 100바이트 길이만 buf에 붙이기

        buf_pos += 100;

    }

}



반응형
블로그 이미지

Bryan_

,
반응형

개발환경: Microsoft Visual Studio 2010, MFC


아는 동생이 MFC로 히스토그램을 만들어서 시연하기 위한 코딩을 도와주면서 MFC를 오랜만에 접하게 되었다. 놀라운 얘기지만, 나는 학부 때 MFC 프로그램을 만들 일이 없었고, 연구실에서도 Java와 C 위주로만 개발하다 보니 MFC를 제대로 배운 적이 없다.


간단하게 윈도우 창에 히스토그램을 그려 주는 코드를 만들어 보면서, 혹시라도 나중에 데이터를 가지고 아주 간단한 시연(demonstration)을 할 때 급히 써먹을 가능성이 있을 것 같아서 기록하게 되었다. 막상 기록은 하게 됐지만 실상은 너무 간단하다.

 - 먼저 X축과 Y축을 원하는 길이만큼 긋고,

 - X축 위에 원하는 너비와 높이만큼 막대기를 배치한다.

끝. ㅡㅡ;


물론 더 보기 좋은 히스토그램을 그리고자 한다면 X축과 Y축 제목을 비롯해 고칠 것이 매우 많겠지만, 일단 기본 코드 위에서 그런 잡다한 작업을 시작하면 될 것이므로 기본 중의 기본만 남기게 되었다.

MFC에는 당연히 사각형을 그려 주는 함수가 있다. 그리기 개체(CClientDC)를 정의하고 FillSolidRect 함수를 이용하면 된다.

CClientDC pDC(this);

pDC.FillSolidRect( 0, 200, 50, 80, RGB(255,0,0) ); // (x,y)좌표: (0, 200), 너비: 50, 높이: 80, 색깔: 빨간색


단지 사각형을 그릴 때의 기준점(원점: (0,0))이 윈도우 창의 왼쪽 위에서 시작하고, Y 좌표값은 아래쪽으로 갈 수록 커진다는 것만 주의하면 된다.


우선 새로운 MFC 프로젝트를 만들 때 빈 윈도우 화면에 ChildView를 하나 만든 채로 시작했다.

프로젝트 이름을 hstorgram_140206으로 했더니 Visual Studio 2010에서 알아서 헤더와 소스 파일은 만들어 주었다.

편의를 위해 헤더 파일(historgram_140206.h)에 원점과 X,Y축 길이, 히스토그램 사각형(막대기)의 크기 등을 미리 정의했다.

// 새로 정의한 변수들

#define ORIGIN_X 20

#define ORIGIN_Y 560

#define X_AXIS_LENGTH 800

#define Y_AXIS_LENGTH 500

#define BAR_WIDTH 25

#define BAR_HEIGHT 20

#define BAR_COLOR RGB(0,255,0) // 녹색


ChildView.cpp 파일에는 onPaint() 함수에 히스토그램 그리는 작업을 했고, 막대기는 반복해서 그리기 때문에 별도의 함수로 만들었다.

/**

 * 단색으로 채워진 사각형을 그립니다.

 *

 * @param x 히스토그램의 x축에서 사각형을 그리게 될 위치

 * @param width 그려지는 사각형의 가로 길이

 * @param height 그려지는 사각형의 세로 길이(y값)

 * @label 해당 사각형의 레이블 값(x축에 적히는 글자)

 */

void CChildView::drawSolidRectangle(int x, int width, int height, CString label)

{

CClientDC pDC(this);

pDC.FillSolidRect(ORIGIN_X+x, ORIGIN_Y-height, width, height, BAR_COLOR);

pDC.SetBkColor( RGB(255,255,255) );

pDC.TextOutW(ORIGIN_X + x + (BAR_WIDTH/2), ORIGIN_Y+1, label);

}


void CChildView::OnPaint() 

{

CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.


// 그리기 객체 초기화

CClientDC pDC(this);


/*

* X축과 Y축 그리기.

* 참고로 (0,0)은 화면상에서 왼쪽 위.

*/

pDC.MoveTo(ORIGIN_X, ORIGIN_Y); // 원점으로 이동

pDC.LineTo(ORIGIN_X + X_AXIS_LENGTH, ORIGIN_Y); // X축 선 그리기

pDC.MoveTo(ORIGIN_X, ORIGIN_Y); // 원점으로 이동

pDC.LineTo(ORIGIN_X, ORIGIN_Y - Y_AXIS_LENGTH); // Y축 선 그리기


/*

* data 읽어오기

*/

// 텍스트 파일이나 DB에서 읽어오고자 할 경우 여기서 값을 로드합니다.



/*

* 색깔이 채워진 사각형(SolidRect) 그리기

 * 여기서는 예제로 a부터 z까지 높이를 20씩 증가시켜 가며 자동으로 막대기를 그렸다.

*/

char ch = 'a'; // 각 사각형의 x축 레이블(테스트 목적으로 a~z 글자를 입력)

int i = 0;

for(i=0; i<26; i++){

drawSolidRectangle(BAR_WIDTH*i, BAR_WIDTH-1, BAR_HEIGHT*i, CString(ch));

ch++;

}

}





Visual Studio 2010 프로젝트 파일(zip): 

histogram_140206_2.zip




반응형
블로그 이미지

Bryan_

,
반응형

평소에 자주 쓰는 텍스트 편집기에서 텍스트 파일 편집 시, 몇번째 줄로 이동하는 명령어의 단축키가 조금씩 달라서 따로 기록하게 되었다.



* VI (리눅스 콘솔 텍스트 편집기)

명령어 모드에서(Esc 눌렀을 때), n번째 라인으로 이동하고자 할 때,

nG

참고로 라인 번호 뒤에 G는 반드시 대문자여야 한다. 

Shift + g로 누르거나, CapsLock 눌러둔 상태에서 그냥 g키를 누르거나 둘 중 하나.


gg (소문자 g 두번)

문서의 첫번째 줄로 이동


G (대문자 G 한번)

문서의 맨 마지막 줄로 이동



* gedit (Ubuntu 기본 텍스트 편집기)

Ctrl + I



* Eclipse IDE

Ctrl + L



* Microsoft Visual Studio

Ctrl + G



* Microsoft Windows Notepad (윈도우 메모장)

"서식 - 자동 줄 바꿈" 설정을 체크 해제한 상태에서만 가능하며,

Ctrl + G



* EditPlus (에디트플러스, 국산 텍스트 편집기)

Ctrl + G



반응형
블로그 이미지

Bryan_

,
반응형

이클립스(Eclipse)에서 맨 처음 Subversive SVN을 설치하고 나서 재시작 후에 SVN을 사용하고자 하면 바로 SVN Connectors 설치 대화상자 뜬다. 실수로 이 대화상자를 끄면 이클립스를 재시작하더라도 두번 다시 같은 대화상자가 뜨지 않는다.


이 경우에는 Help > Install New Software... 를 눌러서 설치 창으로 들어가서 아래 주소를 "Work with:"에 추가한다.

http://community.polarion.com/projects/subversive/download/eclipse/3.0/update-site/


그러면 아래 그림처럼 Subversive SVN Connectors 설치를 진행할 수 있다.


참고로 설치 버전은 윈도우 플랫폼(32bit, 64bit)를 고려해서, 해당하는 플랫폼 중에서 최신 버전을 설치하면 된다.


반응형
블로그 이미지

Bryan_

,