2016-12-11 6 views
0

Посмотрите на это:Создание безопасной NullPointer в отношении к утечкам памяти

char (*options)[MAXLEN]; 
    char *ptr; 
    ptr = strtok(input, " \r\n"); 
    if(!ptr) 
     continue; 
    int i = 0; 
    optionen = malloc(sizeof(*options)); 
    if(!options) 
     die("malloc"); 
    while(ptr){ 
     if(i > 0){ 
      options = realloc(options, (i+1)*sizeof(*options)); 
      if(!options) 
       die("malloc"); 
     } 
     strcpy(options[i], ptr); 
     if(!options[i]) 
      die("strcpy"); 
     ptr = strtok(NULL, " \r\n"); 
     i++; 
    } 


/*create another entry options[i] that is a nullpointer*/ 

Цель в том, что ехес (3) команда требует NullPointer в качестве последней записи к * опциям [] массив для правильной работы.

Проблема: Как я могу добавить еще одну запись в массив, который является указателем NULL? Я понимаю, что я не могу выделить еще options[i] и установить его на NULL, потому что какой-то парень в stackoverflow сказал мне, чтобы я никогда не делал этого (утечка памяти).

Примечание: на входе некоторый массив, который содержит некоторые командную строку - вход (char input[MAXLEN];) и die() просто вызывает perror(), а затем exit()

+2

Не верьте тому, что они сказали. Выделите другую запись и установите ее значение «NULL». –

+0

Можете ли вы дать мне пример строки, как это сделать? –

+0

Правильно ли я читаю и правильно разбираю, что в 'char (* options) [MAXLEN];', 'options' является указателем на массив символов MAXLEN? Это намерение? –

ответ

1

Мое предложение: создать другой массив следующим образом и использовать его в вызове exec.

char** args = malloc((i+1)*sizeof(*args)); 
for (int j = 0; j < i; ++j) 
{ 
    args[j] = options[j]; 
} 
args[i] = NULL; 

execvp(..., args); 
2

Кто сказал вам, что вы «не может выделить другой options[i] и установить его в NULL» было неправильно. Это именно то, что вы делаете.

Однако, у вас есть ошибки в коде, и ошибки свидетельствуют о том, что вы не понимаете, что это означает для «выделить еще один options[i]

char (*options)[MAXLEN]; /* This is wrong */ 
char *ptr; 
ptr = strtok(input, " \r\n"); 
if(!ptr) 
    continue; 
int i = 0; 
optionen = malloc(sizeof(*options)); 
if(!options) 
    die("malloc"); 
while(ptr){ 
    if(i > 0){ 
     options = realloc(options, (i+1)*sizeof(*options)); 
     if(!options) 
      die("malloc"); 
    } 
    strcpy(options[i], ptr); /* This is also wrong */ 
    if(!options[i]) 
     die("strcpy"); 
    ptr = strtok(NULL, " \r\n"); 
    i++; 
} 

Во-первых, char (*options)[MAXLEN] неправильный тип массива и запись в него не может быть установлен в NULL. Вам нужно вместо этого char **options.

Второе, realloc Операция, которую вы уже делаете, фактически выделяет больше options[i] слотов. Но вам также необходимо выделить пространство для самих строк (но не для NULL). Вы делаете это с strdup.

options[i] = strdup(ptr); /* Instead of the "also wrong" line */ 

(в зависимости от того, что input, вы могли бы быть в состоянии уйти только с помощью строки указатели strtok возвращается, но не видя больше кода я не могу быть уверен, что это безопасно.)

И затем, после цикла, вы просто устанавливаете окончательный слот options[i] в NULL, и все готово.

Я бы структурировать петлю немного по-другому, например:

char **options; 
char *ptr; 
size_t i, asize; 

ptr = strtok(input, " \t\r\n"); 
if (!ptr) continue; 

options = 0; 
i = 0; 
asize = 2; 
do { 
    while (i >= asize) { 
     asize *= 2; 
     options = xreallocarray(options, asize, sizeof(char *)); 
    } 
    options[i++] = xstrdup(ptr); 
    ptr = strtok(0, " \t\r\n"); 
} while (ptr); 

while (i >= asize) { 
    asize *= 2; 
    options = xreallocarray(options, asize, sizeof(char *)); 
} 
options[i] = 0; 

execve(options[0], options, environ); 
die("execve"); 

Функция xreallocarray и xstrdup являются нестандартными, но они должны быть в вашей сумке простых функций, которые вы добавляете к каждой программе, что вы пишете , Вот их определения. Они используют функцию die(), которая у вас уже есть.

void * 
xreallocarray(void *optr, size_t nmemb, size_t size) 
{ 
    /* s1*s2 <= SIZE_MAX if both s1 < K and s2 < K where K = sqrt(SIZE_MAX+1) */ 
    const size_t MUL_NO_OVERFLOW = ((size_t)1) << (sizeof(size_t) * 4); 

    if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 
     nmemb > 0 && SIZE_MAX/nmemb < size) { 
     errno = ENOMEM; 
     die("malloc"); 
    } 

    void *rv = realloc(optr, size * nmemb); 
    if (!rv) 
     die("malloc"); 
    return rv; 
} 

char * 
xstrdup(const char *s) 
{ 
    size_t n = strlen(s) + 1; 
    char *rv = malloc(n); 
    if (!rv) 
     die("malloc"); 
    memcpy(rv, s, n); 
    return rv; 
} 
+1

Zwol, я настоятельно рекомендую вам использовать стандартные функции, такие как 'realloc', а не использовать ваши собственные собственные функции. Ваши функции не задокументированы и не объясняют, что они делают, или почему то, что они делают, необходимо, ни для какой платформы они написаны. –