Передача параметров и присвоение им значений приводит к ошибке во время выполнения - PullRequest
0 голосов
/ 01 февраля 2012

Итак, у меня есть следующий код:

void emptyString(char* token, int size) {
    for (int i=0; i < size; i++) token[i] = '\0';
}

    void setDefaults(char uloginName[], char *home_directory, char *password, char *shell, char *gecos) {
        emptyString(home_directory, sizeof(home_directory) - 1);
        strcat(home_directory, "home/home/");
        strcat(home_directory, uloginName);
    }

    int main(){
        char buffer[256];
        AccountInfo *tempAccount;
        UserDB users;
        char uloginName[9] = "Smith";
        char homeDirectory[33];
        int userID;
        int groupID;
        char password[17];
        char shell[17];
        char gecos[65];
        int i, j, k;
        char flag[3];
        char IDString[6];
        char command[11];
        char blank = ' ';

    setDefaults(uloginName, homeDirectory, password, shell, gecos);
    return 0;
    }

Когда я запускаю этот код в Visual Studio, я получаю всплывающее окно с надписью

Ошибка проверки времени выполнения # 2 - стек вокруг переменной 'users' был поврежден

Это вызвано строками кодов в методе setDefaults(). Я надеялся, что кто-то помог мне исправить код. Мое намерение состоит в том, чтобы установить значение home_directory равным " home / home / userloginname ", где userloginname также будет одной из передаваемых переменных.

РЕДАКТИРОВАТЬ: Я только что обнаружил, что в моем коде пролем является strcat() метод. Если я использую strcpy() для первого, он работает нормально, но как только я хочу добавить больше, он показывает мне всплывающее окно, в котором говорится, что переменная users повреждена. Вот код для класса userDB:

class UserDB
{
private:
    AccountInfo* _accounts[200]; // store up to 200 accounts
    unsigned int _size; // number of account stored
    unsigned int _nextUid; // next user id to be assigned
    unsigned int _defaultGid; // default group id
    // other private methods necessary for this class
public:
    // constructors(empty), destructor
    void adduser( AccountInfo* newUser);
    void    showUsers();
    void    showPasswd();
    void    finger(char* userLoginName);class
    int size(); // return the number of accounts stored (_size)
    // and other public methods (mutators/setters, accessors/getters)
};

код, прямо сейчас, как и здесь. Возможно, мне нужно создать конструктор, деструктор или еще что-нибудь, но как новичок, у меня нет возможности узнать, что на самом деле вызывает ошибку и что ее нужно исправить.

РЕДАКТИРОВАТЬ: Итак, через некоторое время я выяснил, что именно strcat () является причиной ошибки, однако мне нужно сделать то, что, как утверждает strcat, делает. Вот копия моего полного кода http://ideone.com/A5iWh, так что тот, кто заинтересован, может сообщить мне, что изменить, потому что я не знаю, что еще делать. Спасибо.

Ответы [ 4 ]

1 голос
/ 01 февраля 2012

Известные проблемы:

// in getNextToken
while ((buffer[i] != delimeter) && (i < 256) && (j < tokenSize))
    token[j++] = buffer[i++];

Нет проверки, что вы достигли конца содержимого buffer[], кроме проверки длины. Что если cin.getline(buffer) будет читать «имя пользователя p mypasswd»? Затем:

в строке 150, копия в command заполняется command, но никогда не ставит завершающий ноль в конце. Может быть, это не проблема ... в строке 153 чтение в uloginName также не вставляет завершающий нулевой символ. в строке 170 чтение в password читает 16 байтов. Возможно, вам повезет с нулевым терминатором, если пароль был достаточно коротким.
1 голос
/ 01 февраля 2012
emptyString(home_directory, sizeof(home_directory) - 1);

У вас есть проблема здесь:

sizeof(home_directory)

Этот оператор дает вам размер указателя home_directory, а не массива.
Если вам нужен размер массива внутри функции, вам придется явно указать его как параметр функции.

Кроме того, ваши переменные не инициализируются, что приводит к неопределенному поведению.
В частности, во фрагменте кода показано uloginName.
Вам нужно будет инициализировать все ваши переменные, чтобы они не вызывали проблем во всем проекте.

0 голосов
/ 01 февраля 2012

Ваше сообщение об ошибке указывает на «переполнение стека». У вас есть какой-то буфер фиксированного размера в стеке вашей программы, и вы записываете в него больше, чем может вместить буфер.

Всякий раз, когда вы объявляете локальную переменную в C или C ++, для нее выделяется некоторое хранилище в стеке выполняющейся функции. Позвольте мне привести пример.

#include <stdio.h>

int main()
{
    short above=0;
    char buffer[1];
    short below=0;

    strcpy(buffer, "Hello,");
    strcat(buffer, " world!");

    printf("%d %d %s", above, below, buffer);
}

Итак, я объявил buffer, что достаточно места для хранения 1 байта. Я пытаюсь вставить в него 14 байтов "Hello, world!\0". Что я получу при запуске этой программы?

27762 0 Hello, world!

Теперь я явно установил «выше» на 0. Как это стало 27762? Ну, вот иллюстрация того, что на самом деле происходит:

    Stack:
|        ....         |                              |   ...  |
| misc platform stuff |                              | d!\0...|
|---------------------|                              |--------|
| storage for 'above' | 2 bytes = sizeof(short)      |   rl   |
|---------------------|                              |--------|
| padding/cookie      | system dependent             |ello, wo|
|---------------------|                              |--------|
| storage for 'buffer'| 1 byte = sizeof(buffer)  ->  |   H    | 
|---------------------|                              |--------|
| padding/cookie      | system dependent             |  ? ? ? |
|---------------------|                              |--------|
| storage for 'below' | 2 bytes = sizeof(short)      |  0  0  |
|      ...            |

Когда я пишу в buffer, первый байт попадает туда, где он должен быть. Затем следующие несколько байтов начинают записываться в область «padding / cookie». В конце концов эта область переполняется, и мы продолжаем перезаписывать следующую более высокую вещь, «выше».

Быстрая проверка показывает нам, что 27762 - это то, как моя машина интерпретирует символы rl в середине "мира!" как short.

Теперь такими ошибками являются переполнения стекового буфера или "переполнение стека". Злонамеренный пользователь может использовать некоторые случаи переполнения стека, чтобы взять под контроль вашу программу и заставить ее делать совершенно разные вещи по сравнению с тем, для чего она предназначена. Эксплуатация переполнения стека является проверенной и проверенной техникой взлома.

Настолько, что разработчики компиляторов и разработчики операционных систем взяли на себя стратегию "глубокой защиты", чтобы предотвратить использование переполнений стека. В идеале, если некоторым пользователям удастся перезаписать неверную часть стека, инструментальная цепочка попытается сделать единственно разумную вещь: немедленно завершить работу.

В этом конкретном случае компилятор вставляет специальное трудно угадываемое значение сразу после хранилища для «буфера», называемого «стека cookie». Когда он оставляет main, он проверяет, что «стек cookie» не изменился. Если это так, то произошло что-то непослушное (возможно, переполнение стека), и поэтому программа немедленно завершает работу с отображаемым диалоговым окном.

Как мы можем исправить переполнение стека? Код в обороне. Никогда не звоните strcpy, strcat, sprintf или их различным друзьям. Вместо использования буферов фиксированного размера (например, char homeDirectory[33];) используйте динамические средства, такие как std::string homeDirectory;, для управления строками. При правильном использовании невозможно переполнить std::string таким образом, что непреднамеренная память будет перезаписана.

0 голосов
/ 01 февраля 2012
strcat(home_directory, uloginName);
                       ^^^^^^^^^^ uninitialized

Причина в том, что char uloginName[9]; не инициализируется внутри main(), который передается в setDefaults(...), и, таким образом, не гарантированно является строкой с нулевым окончанием .

Возможно, буфер выходит за пределы допустимого, и код переходит в неопределенное поведение .

Обновление : из кода, который вы размещено в ссылке , похоже в беспорядке.Вы не инициализировали массивы символов, как я уже говорил ранее.Более того, я не вижу выполненных проверок диапазона, поэтому буфер может легко переполниться.

Например, uloginName просто имеет размер 9, и весьма вероятно, что значение переменной k можетбыть больше, чем это.Что вызовет переполнение стека и повредит значения соседних переменных, объявленных рядом с ним.Попробуйте использовать std::string вместо обнаженных массивов, если вам пока не удобна проверка границ.

...