2010-03-15 5 views
0

내 함수는 다른 것들 중에서도 인수가있는 명령을 구성하는 단어에 대한 포인터의 NULL 종료 배열을 포함하는 구조체를 전달 중입니다.더 많은 char 포인터 목록으로 char 포인터 배열을 덮어 쓰는 방법은 무엇입니까?

인수 목록에서 glob match를 수행하여 전체 파일 목록으로 확장 한 다음 전달 된 인수 배열을 새 확장 된 것으로 대체하려고합니다.

globbing이 제대로 작동합니다. 즉, g.gl_pathv가 예상 파일 목록으로 채워집니다. 그러나, 주어진 구조체에이 배열을 복사하는 데 문제가 있습니다.

#include <glob.h> 

struct command { 
    char **argv; 
    // other fields... 
} 

void myFunction(struct command * cmd) 
{ 
    char **p = cmd->argv; 
    char* program = *p++; // save the program name (e.g 'ls', and increment to the first argument 

    glob_t g; 
    memset(&g, 0, sizeof(g)); 
    g.gl_offs = 1; 
    int res = glob(*p++, GLOB_DOOFFS, NULL, &g); 
    glob_handle_res(res); 
    while (*p) 
    { 
     res = glob(*p, GLOB_DOOFFS | GLOB_APPEND, NULL, &g); 
     glob_handle_res(res); 
    } 

    if(g.gl_pathc <= 0) 
    { 
     globfree(&g); 
    } 

    cmd->argv = malloc((g.gl_pathc + g.gl_offs) * sizeof *cmd->argv); 

    if (cmd->argv == NULL) { sys_fatal_error("pattern_expand: malloc failed\n");} 
    // copy over the arguments 
    size_t i = g.gl_offs; 
    for (; i < g.gl_pathc + g.gl_offs; ++i) 
     cmd->argv[i] = strdup(g.gl_pathv[i]); 

    // insert the original program name 
    cmd->argv[0] = strdup(program); 
    ** cmd->argv[g.gl_pathc + g.gl_offs] = 0; ** 
    globfree(&g); 
} 

void 
command_free(struct esh_command * cmd) 
{ 
    char ** p = cmd->argv; 
    while (*p) { 
     free(*p++); // Segfaults here, was it already freed? 
    } 
    free(cmd->argv); 
    free(cmd); 
} 

편집 1 :에서 팁을 편집 MEM 관리 : 추가 전화
편집 3은 calloc하기 : 또한, 나는 cmd->는 argv [0]
편집 2로 나는 다시 거기에서 프로그램을 고수 할 필요가 실현 알록
편집 4 : ALOK
편집 (5)에서 더 많은 정보 : 명령 구조체 마지막으로

를 해제 할 때 거의 .. 응용 프로그램의 세그먼테이션 폴트 (segfault) 작업 :

: 나는 그래서 줄을 추가, 종단 NULL 누락 된 것 같다
cmd->argv[g.gl_pathc + g.gl_offs] = 0; 

이 효과가있는 것으로 보입니다.

+0

이제 작동합니까? 그렇지 않다면 어떤 오류가 발생합니까? 또한 가장 최근의 편집 내 대답을 참조하십시오. 'paths [0]'에 대해 두 번,'malloc'에 한 번,'strdup '으로 다시 공간을 할당하고 있습니다. –

+0

예, 그 코드는 무척 까다 롭습니다. 최신 편집을보십시오. 새 배열에 액세스 할 때 여전히 충돌이 발생합니다. 아마도 \ 0 문자가 셔플에서 길을 잃고 있습니까? – Casey

+0

'cmd-> argv [g.gl_pathc + g.gl_offs] = '\ 0';'에서' '\ 0''은'NULL'과 같은'0'과 같습니다. ' '\ 0' '대신에'NULL'을 사용하십시오. –

답변

1

argvchar *의 포인터 배열입니다. 즉, argv에는 argcchar * 값을위한 공간이 있습니다. 그 이상의 많은 char * 값을 복사하려고하면 오버플로가 발생합니다.

glob 호출 결과는 argc 개 이상이 gl_pathv 필드 (즉, gl_pathc > argc)입니다. 이것은 정의되지 않은 동작입니다.

은 아래 코드와 유사하다 :

/* Wrong code */ 
#include <string.h> 

int a[] = { 1, 2, 3 }; 
int b[] = { 1, 2, 3, 4 }; 
memcpy(a, b, sizeof b); 

해결 방법 : 새 char **gl_pathv을 복사 할 수있는 새로운 공간을이 glob_t 직접 구조체와 함께 작동, 또는 할당해야 하나 :

char **paths = malloc(g.gl_pathc * sizeof *paths); 
if (paths == NULL) { /* handle error */ } 
for (size_t i=0; i < g.gl_pathc; ++i) { 
    /* The following just copies the pointer */ 
    paths[i] = g.gl_pathv[i]; 

    /* If you actually want to copy the string, then 
     you need to malloc again here. 

     Something like: 

     paths[i] = malloc(strlen(g.gl_pathv[i] + 1)); 

     followed by strcpy. 
    */ 
} 

/* free all the allocated data when done */ 

수정 후 : 수정 후 :

cmd->argv = calloc(g.gl_pathc, sizeof(char *) *g.gl_pathc); 

이면 작동하지만 각각 argv[1] ~ argv[g.gl_pathc + g.gl_offs - 1]struct glob에 의해 "소유"된 char *입니다. memcpy 호출은 포인터 만 복사합니다. 나중에 globfree()을 수행하면 해당 포인터가 더 이상 의미가 없습니다. 따라서 사용하고자하는 문자열을 복사해야합니다.

size_t i; 
cmd->argv = malloc((g.gl_pathc+g.gl_offs) * sizeof *cmd->argv); 
for (i=g.gl_offs; i < g.gl_pathc + g.gl_offs; ++i) 
    cmd->argv[i] = strdup(g.gl_pathv[i]); 

이렇게하면 문자열의 개인 복사본을 가질 수 있습니다. 완료되면 무료로하십시오 (및 argv).

코드에 몇 가지 다른 문제가 있습니다.당신이 역 참조의 값을 사용하지 않을 때문에 당신은 *p++하고있는

  1. , 당신은 p++해야한다.
  2. 정말 반환 값 glob을 확인해야합니다.
  3. paths 변수에 g.gl_pathc + 1 요소가 필요하며 g.gl_pathc이 필요 없습니다. (또는 정확히 올바르게 g.gl_pathc + g.gl_offssizeof *paths 바이트를 할당해야합니다.
  4. for 문자열을 복사 할 루프는 for (j=1; j < g.gl_pathc + g.gl_offs; ++j)이어야합니다.
  5. 쉘이 덩어리를 확장하는 것을 방지해야합니다. 즉, ./a.out * 대신 ./a.out '*'으로 전화하십시오.
+0

내 함수가 명령 구조체에 전달되는 아이디어는 내 함수가 실행되기 전에 명령 문자열에서 일부 연산을 수행하는 정렬의 처리기라는 것입니다. 따라서 cmd의 argv 값을 수정해야합니다. – Casey

+0

그러나'cmd'의'argv' 엘리먼트는 어디에서 왔습니까? 배열이라면 C에서 불법 인'cmd-> argv = ... '만 말할 수 없다.'int a [] = {1, 2}; 뒤에' a = malloc (...);'. –

+0

신경 쓰지 마라, 내 뇌가 약혼 한 게 아니야. 나는'struct cmd'의 정의를 "놓쳤다". –

0

sizeof (char *)에 의해 g.gl_pathc를 여러 번 배정 할 필요가 없습니까?

+0

흠, 그래 ..하지만 문제의 일부는 cmd-> argv가 g.gl_pathv보다 작은 것 같습니다. 초기 argv가 "ls"와 "* .h"의 두 요소로 구성되어 있다면 * .h는 파일 이름 100 자로 확장 될 수 있습니다. – Casey

+0

좋은 점. 방금 저지른 벌레를 발견했습니다. – bmargulies