Странный побочный эффект с Malloc () - PullRequest
1 голос
/ 13 декабря 2010

Итак, я пишу программу на C для простой оболочки.Не слишком сложно, но я столкнулся с одной действительно странной проблемой, которую не могу объяснить.Я пытаюсь создать двумерный массив в структуре для представления команды и ее аргументов.Например, для команды "ls -l" я хотел бы иметь первый элемент "ls" и второй "-l".Кажется, работает нормально, кроме того, что malloc меняет "ls" на "ms".То же самое для других команд, первый символ увеличивается;не до malloc, а сразу после.

Это кусок кода, о котором идет речь ....

    printf ("PRE MALLOC: %c\n", ret_val->args[0][0]);
    printf ("[0] %p\n", ret_val->args[0]);
    ret_val->args[1] = (char*) malloc ((3) * sizeof (char));
    printf ("[0] %p\n", ret_val->args[0]);
    printf ("[1] %p\n", ret_val->args[1]);
    printf ("POST MALLOC: %c\n", ret_val->args[0][0]);

Все, что я пытаюсь сделать, это выделить 3 (-l+ нулевой) массив символов для хранения "-l" в аргументах [1].Они на самом деле тоже не будут жестко закодированы, но я подумал, что это поможет улучшить ситуацию.

Результат дал это ...

PRE MALLOC: l

[0] 80613b0

[0] 80613b0

[1] 80613b8

POST MALLOC: m

Так что два адреса не перекрываются или что-то странноено первый символ первого массива увеличивается?Извините, если я пропускаю что-то глупое.Но я не могу придумать причину, по которой это могло бы произойти.

Любые идеи?

Спасибо,

Вот гораздо больше кода для некоторого контекста.

int lcv;
int numargs;
int numchars;
int offset;
int bool;

TCommand* ret_val;
char** tmp;

ret_val = (TCommand*) malloc ( sizeof (TCommand) );
ret_val->cmd = NULL;
ret_val->args = NULL;

/* CMD */
lcv = 0;
numargs = 0;
numchars = 0;
offset = 0;

/* Remove initial whitespace */
while (input[offset] == ' ')
{
    ++offset;
}

lcv = offset;

/* Loop through command string */
while ( input[lcv] != ' ' && input[lcv] != 0 && input[lcv] != '&')
{
    ++numchars;
    ++lcv;
}

ret_val->cmd = (char*) malloc ( (numchars+1) * sizeof(char));

/* Copy to command string */
memcpy (ret_val->cmd, &(input[offset]), (numchars * sizeof (char)));
ret_val->cmd[numchars] = 0;
offset += numchars;

/* Copy command string into first argument */
ret_val->args = (char**) malloc ( sizeof (char*));
memcpy (ret_val->args[numargs++],ret_val->cmd, (numchars+1) * sizeof(char));

bool = 1;
while ( bool )
{

    /* Remove initial whitespace */
    while (input[offset] == ' ')
    {
        ++offset;
    }

    lcv = offset;

    if ( input[lcv] == 0 )
    {
        bool = 0;
    }
    else
    {
        ++numargs;
        tmp = (char**) realloc (ret_val->args, numargs * sizeof (char*));
        ret_val->args = tmp;
        numchars = 0;

        while ( input[lcv] != ' ' && input[lcv] != 0 &&
            input[lcv] != '&')
        {
            ++numchars;
            ++lcv;
        }

                printf ("PRE MALLOC: %c\n", ret_val->args[0][0]);
                printf ("[0] %p\n", ret_val->args[0]);
                    ret_val->args[1] = (char*) malloc ((2) * sizeof (char));
                printf ("[0] %p\n", ret_val->args[0]);
                printf ("[1] %p\n", ret_val->args[1]);
                printf ("POST MALLOC: %c\n", ret_val->args[0][0]);
                fflush(stdout);
        memcpy (ret_val->args[numargs-1],&(input[offset]),numchars * sizeof (char));
        ret_val->args[numargs-1][numchars] = 0;
        offset += numchars;
    }
}

Ответы [ 4 ]

4 голосов
/ 13 декабря 2010

Этот код:

/* Copy command string into first argument */
ret_val->args = (char**) malloc ( 2 * sizeof (char*));
memcpy (ret_val->args[numargs++],ret_val->cmd, (numchars+1) * sizeof(char));

Копирует через неинициализированный указатель ret_val->args[0]. Попробуйте:

/* Copy command string into first argument */
ret_val->args = malloc(2 * sizeof ret_val->args[0]);
ret_val->args[numargs] = malloc(numchars + 1);
memcpy(ret_val->args[numargs++], ret_val->cmd, numchars + 1);

(Обратите внимание, что sizeof(char) определяется как 1 языком).

0 голосов
/ 13 декабря 2010

Это звучит как классический пример повреждения кучи.

Скорее всего, вы видите результат вызова malloc(), перезаписывающего строку, на которую args[0] указывает возвращаемое значение.Это может произойти, если в массиве args на самом деле недостаточно места для второго аргумента.Записывая в args[1], вы перезаписываете содержимое строки, на которую указывает argv[0], и я подозреваю, что вы выделяете ее с помощью вызова strdup() или аналогичного сразу после выделения массива args.

Поскольку куча растет вверх, и при отсутствии промежуточных вызовов free(), выход за границы динамически распределенного массива повышает вероятность попадания в область, выделенную сразу после этого.

Я рискнуугадать и рекомендовать проверить выделенный размер для массива args, распечатав аргументы для вызова realloc() и проверив его возвращаемое значение.

EDIT:

Видимо, не в этомдело.Кажется, что указатель argv[0] может быть фактически неинициализирован, не вызывая ошибки сегментации.Интересно ...

0 голосов
/ 13 декабря 2010

Полагаю, нам нужно посмотреть, как распределяется args [0] и как ему присваивается значение.

Я могу сделать несколько предложений, хотя они не решат проблему выделения:

  1. Нет необходимости разыгрывать результат malloc(), и хотя у человека ограниченная возможность изменять тип в уже написанной программе на C, нет никаких оснований для намеренно ниже уровень абстракции путем открытого кодирования дубликата информации о типе.

    Старые тексты и примеры старого кода часто приводят malloc(), потому что C не всегда имел тип void *, и даже после его появления люди писали в старом стиле по привычке и для переносимости кода старым компиляторам. Но вряд ли вам когда-нибудь понадобится компилировать для PDP-11.

  2. sizeof(char) по C99, 1, так что можно просто сказать malloc(3), и это читается немного легче, потому что оно короче. И если вы знаете, что это "-l", вы можете просто использовать "-l".

0 голосов
/ 13 декабря 2010

Проблема не в фрагменте, который вы показываете; это где-то в коде, который вы не показываете.

Итак, вам нужно построить свой пример с нуля - показать объявления структуры, управление памятью и копирование, которое вы делаете для структур.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...