[질문]mmap를 사용할때 에러가 나요..ㅡ.ㅡ

attochip의 이미지

안녕하세요?
c초보자인데요..UNIX로 짰습니다..
메모리 맵을 이용해서 파일 카피 프로그램을 짜볼려는데
실행하면 계속 버스 오류(Bus error) (메모리가 덤프됨)
이라는 오류가 나옵니다.
프로그램은요...

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main(int argc, char *argv[])
{
void fatal(char *);
int source, object;
int count;
char *smap, *omap;

if(argc < 2)
{
puts("사용법 : mmap source object");
exit(0);
}

if((source = open(argv[1], O_RDONLY)) < 0)
fatal("read open");

if((object = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
fatal("write open");

count = lseek(source, 0, SEEK_END);
smap = mmap(0, count, PROT_READ, MAP_SHARED, source, 0);
omap = mmap(0, count, PROT_WRITE|PROT_READ, MAP_SHARED, object, 0);

memcpy(omap, smap, count);

munmap(smap, count);
munmap(omap, count);

close(source);
close(object);

}

void fatal(char *error_name)
{
perror(error_name);
exit(1);
}
입니다..

제 생각에는 memcpy에서 계속 에러가 나거든요..ㅡ.ㅡ

왜 그런지 모르겠습니다..

컴파일 할때 다른 옵션은 붙여줘야 하나요?

저는 cc -o mmap mmap.c (파일 이름이 mmap.c일때)

라고 했거든요..

실행은 abc라는 파일이 있다고 가정하구요..

mmap abc abcd

라고 하면은 "버스 오류(Bus Error) (메모리가 덤프됨)"

라는 메세지가 뜸니다..

아..아시는분 제발 답변 부탁드립니다..

저로서는 이제 한계가..ㅡ.ㅡ

stoneshim의 이미지

int main(int argc, char *argv[])
...
        count = lseek(source, 0, SEEK_END);
/* 이부분을 넣어주세요 - start */
        if ( lseek( object , count -1 , SEEK_SET ) == -1 )
                fatal("lseek object");
        if ( write( object , " " , 1 ) != 1 )
                fatal("write space to last byte of object");
/* 이부분을 넣어주세요 - end */

        if((smap = mmap(0, count, PROT_READ, MAP_SHARED, source, 0)) < 0 )
                fatal("mmap smap");
...
}

count 구한 후 smap= mmap() 하기 전에 위의 코드를 넣어주세요.

왜 그랬는지는 기억이 안나는데... write용 파일을 새로 만드는 경우에는 저런식으로 space(사실 아무 값이나 상관없겠죠)를 마지막 바이트에 채워주면 잘 되었던것 같습니다.

이게 mmap 버그인지 원래 저렇게 해야하는건지 잘 모르겠네요.

왜 그런지 아시는 분은 설명을 달아주세요

우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자

최종호의 이미지

APUE에 보니까 그 이유가 나와있네요.
pp. 411-413 까지에 mmap을 이용한 파일복사 예제가 나와있는데,
output 파일의 사이즈를 설정할 필요가 있다고 합니다.
파일의 사이즈를 설정한다고 하는 것이 제가 생각하기로는 그 파일을 위한 공간을 할당한다는 의미로 해석을 해야 하는 것 같습니다. (사용자가 파일연산을 통하지 않고 곧바로 stat 정보의 file size 를 변경할 수 없지 않나요?)
포인터를 사용해서 strcpy() 를 할 때, 대상 포인터가 가리키는 영역이 미리 할당되어 있어야 하는 것과 비슷한 생각이 드는데요. 여기서 포인터가 mmap한 주소가 되겠고, 실제파일영역이 mmap을 통해서 가리키는 저장공간이 되겠죠.

테스트를 해 보기 위해서 a.out 을 a.out2 라는 파일로 복사해 보았습니다.
% cp a.out a.out2
% a.out a.out a.out2
=> Bus Error

코드 상에 O_TRUNC 가 있어서 cp를 통해 a.out 을 a.out2 로 복사해 놓아도 open이 되면 0 byte로 변하게 되어서 여전히 Bus Error가 발생했습니다.
open의 O_TRUNC를 빼고 다시 컴파일해서 수행했더니 정상수행됐습니다.

복사하려는 파일보다 더 큰 크기를 가지는 파일을 대상파일로 설정해 보았습니다. 이 경우도 O_TRUNC는 빼 놓았구요.

% cp biggerfile cli.d
% ls -al cli cli.d
...
-rwxr-xr-x 1 ... 9888 1월 5일 1853 cli
-rw------- 1 ... 23720 3월 29일 1619 cli.d
% a.out cli cli.d
...
-rwxr-xr-x 1 ... 9888 1월 5일 1853 cli
-rw------- 1 ... 23720 3월 29일 1619 cli.d

정상수행됐지만 대상파일의 크기가 이전파일크기를 그대로 유지하네요. 예상됐던 결과지요. 아마 cli.d 의 앞쪽 9888 바이트만큼은 cli와 동일하겠죠?

결론.
정상 수행을 위해서는 O_TRUNC 옵션을 빼면 안 되겠고,
대상 파일크기 설정을 위해서는 대상파일이 원본파일만큼 크기를 가지도록 보장해 주어야 하겠고, lseek() 후 맨 끝에 한바이트 써주는 식으로 해주면 된다.

해당 원문입니다. 참조하세요.

Program 12.14 copies a file (similar to the cp(1) command) using memory mapped I/O. We first open both files and then call fstat to obtain the size of the input file. We need this size fo the call to mmap for the input file, plus we need to set the size of the output file. We call lseek and then write one byte to set the size of the output file. If we don't set the output file's size, the call to mmap for the output file is OK, but the fist reference to the associated memory region generates SIGBUS. ...

attochip의 이미지

아..두분다 답변 감사합니다..

이제서야 모든 의문이 다 풀리네요..^^

그럼..꾸벅~

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.