Почему добавление строки cout в этот метод мешает моей программе отключить исключение переполнения буфера в Windows? - PullRequest
1 голос
/ 24 декабря 2011

У меня есть объект с помощью следующего метода:

int PathSubstitution::updateField(Field4memo &field, int record_id, int field_id) const
{
    int type = field.type();
    if((type == r4str) || (type == r4memo) || (type == r4unicode))
    {
        string value = field.str();
        trim(value);
        if(!substituteDriveLetters(value))
            return -1;
        if(!substituteGridMount(value))
            return -1;

        return field.assign(value.c_str(), value.length());
    }
    return r4success;
}

Когда я собираю этот код с моим профилем отладки в Visual Studio C ++ 2010, все работает просто отлично.Этот метод вызывается 4 раза для четырех уникальных объектов Field4memo, и он работает.

Когда я создаю этот код с моим профилем Release, метод работает при первом вызове, но заставляет Vista Enterprise отображать «программу»..exe перестал работать "диалоговое окно.В области «Просмотр сведений о проблеме» окна указано:

Problem signature:
  Problem Event Name:   BEX
  Application Name: program.exe
  Application Version:  0.0.0.0
  Application Timestamp:    4ef4edc6
  Fault Module Name:    program.exe
  Fault Module Version: 0.0.0.0
  Fault Module Timestamp:   4ef4edc6
  Exception Offset: 0000668a
  Exception Code:   c0000409
  Exception Data:   00000000
  OS Version:   6.0.6002.2.2.0.256.4
  Locale ID:    1033
  Additional Information 1: 6243
  Additional Information 2: 0d5daf38e26c963685a835e6f40ff03d
  Additional Information 3: aa53
  Additional Information 4: 5d02a603659cce53ff840117c3a9c7a7

Имя события BEX указывает на переполнение буфера.Но какой буфер я не могу сказать.

Вот где мне это странно ...

Когда я меняю этот метод и добавляю ненужную строку cout, он работает спрофиль выпуска:

int PathSubstitution::updateField(Field4memo &field, int record_id, int field_id) const
{
    int type = field.type();
    if((type == r4str) || (type == r4memo) || (type == r4unicode))
    {
        // THIS IS THE NEW LINE I ADDED RIGHT BELOW HERE!!!
        cout << endl;
        string value = field.str();
        trim(value);
        if(!substituteDriveLetters(value))
            return -1;
        if(!substituteGridMount(value))
            return -1;

        return field.assign(value.c_str(), value.length());
    }
    return r4success;
}

Я не могу сказать, почему метод падает с профилем выпуска или почему добавление строки cout решает проблему сбоя.Мне неудобно просто принимать ответ "cout исправляет" - может кто-нибудь помочь мне понять, в чем моя проблема и почему cout исправляет ее?Как вызов cout спасает меня от переполнения буфера здесь?

Редактировать: был запрошен некоторый дополнительный контекст для вызова этого метода.Это называется в цикле.С тестовым вводом, который я использую, он вызывается 4 раза.Вызывающая его функция выглядит следующим образом:

int PathSubstitution::updateRecord(Data4 &dbf, int record_id) const
{
    // Update all fields
    int numFields = dbf.numFields();
    for(int i = 1; i <= numFields; i++ )
    {          
        Field4memo field(dbf, i);
        int rc = updateField(field, record_id, i);
        if(rc != r4success)
            return rc;
    }
    return r4success;
}

Редактировать 2: очистка буфера cout также устраняет проблему переполнения, если cout.flush() вызывается из метода PathSubstitution::updateField и доreturn field.assign(value.c_str(), value.length()); строка.

Редактировать 3: Это многообещающе.Если я закомментирую вызовы методов substituteDriveLetters() и substituteGridMount(), программа не завершится сбоем.Так что это как-то связано с этими вызовами методов (которые используют pcre для выполнения некоторых подстановок строк регулярных выражений).

Редактировать 4: Если я закомментирую просто метод substituteDriveLetters ()работает.Так что теперь у меня есть главный подозреваемый.Предполагается, что этот метод заменяет букву диска в пути соответствующим значением UNC.Ни одно из полей в моем тестовом вводе не является путем к файлу, так что это должно быть нулевой операцией, если речь идет о преобразовании данных.

bool PathSubstitution::substituteDriveLetters(string &str, string::size_type offset) const
{
    int offsets[6];
    int groups = pcre_exec(drivePattern, NULL, str.c_str(), str.size(), 0, 0, offsets, sizeof(offsets));
    if(groups < 0)
    {
        switch(groups)
        {
        case PCRE_ERROR_NOMATCH:
        case PCRE_ERROR_PARTIAL:
            return true;
        case PCRE_ERROR_NOMEMORY:
            cerr << "WARNING: Out of memory." << endl;
            break;
        case PCRE_ERROR_BADUTF8:
        case PCRE_ERROR_BADUTF8_OFFSET:
            cerr << "WARNING: Bad UNICODE string." << endl;
            break;
        default:
            cerr << "WARNING: Unable to substitute drive letters (Err: " << groups << ")" << endl;
            break;
        }
        return false;
    }

    char driveLetter = toupper(str[offsets[2]]);
    DriveMap::const_iterator i = driveMap.find(driveLetter);
    if(i == driveMap.end())
    {
        cerr << "ERROR: The " << driveLetter << " drive is not mapped to a network share." << endl;
        return false;
    }

    string::iterator start = str.begin() + offsets[0];
    string::iterator end = str.begin() + offsets[1];
    str.replace(start, end, i->second);

    return substituteDriveLetters(str, offsets[1]);
}

1 Ответ

2 голосов
/ 24 декабря 2011

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

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

Если вам нужна помощь в анализе актуальной проблемы, вам нужно опубликовать полный скомпилированный пример. На данный момент мы ничего не знаем о Field4memo, trim, substituteDriveLetters или substituteGridMount для начинающих.

Редактировать Возможно, вы захотите вставить дополнительные проверки для выполняемых вами строковых операций.

// need to check that offsets[2] >= 0 and < str.size()
char driveLetter = toupper(str[offsets[2]]);

// need to check that offsets[0] >= 0 and <= str.size()
string::iterator start = str.begin() + offsets[0];

// need to check that offsets[1] >= 0 and <= str.size()
string::iterator end = str.begin() + offsets[1];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...