Ошибка проверки времени выполнения # 2 Отладка MSVC только с utf8proc - PullRequest
0 голосов
/ 08 сентября 2018

Я довольно новичок в c ++, и это одна из моих первых попыток сделать что-то относительно большое / полезное, поэтому, если есть какие-либо явные ошибки, которые не связаны с моим вопросом, конструктивный комментарий приветствуется.

Для некоторых операций, связанных с utf-8, я использую библиотеку C utf8proc .

Проблема

При сборке с последней версией MSVC 15 дляцель отладки, запускающая тестовую программу, использующую этот код (в основном такой же простой, как печать результатов этой функции), выдает ошибку:

Ошибка отладки!

[Некоторая информация о том, какой exe-файл завершился неудачно]

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

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

Следует отметить несколько интересных случаев (они были протестированы с помощью gcc):

Во-первых, память codepoint и character иногда кажется случайным образом измененной (отсюда и хакерское смягчение: сохранение codepoint в codepointCopy).

Во-вторых, character, однажды закодированная,иногда имеет нечетные завершающие символы (однако я полагаю, что из-за неинициализированной памяти попытки установить память в character на 0 вручную с помощью memset не помогли, что-то очевидно отсутствует?), отсюда и хакерский .substr(0, charSize), который до сих пор работает нормально.

Код

#include <string>

#include "../include/utf8proc.h"

std::string calculateUnicodeNormalization(const std::string &in, const std::string &mode) {
    auto pString = (const utf8proc_uint8_t*) in.c_str();

    utf8proc_uint8_t* pOutString;
    // These two functions are from c and use malloc to allocate memory, so I free with free()
    if (mode == "NFC") {
        pOutString = utf8proc_NFC(pString);
    } else {
        pOutString = utf8proc_NFD(pString);
    }

    // Converts to a string
    std::string retString = std::string((const char*) pOutString);
    // Frees what was allocated by malloc
    free(pOutString);

    return retString;
}

std::string removeAccents(const std::string &in) {
    std::string decomposedString = calculateUnicodeNormalization(in, "NFD");
    auto pDecomposedString = (const utf8proc_uint8_t*) decomposedString.c_str();

    size_t offset = 0;
    std::string rebuiltString;
    // Iterates through all of the characters, adding to the "offset" each time so the next character can be found
    while (true) {
        utf8proc_int32_t codepoint;

        // This function takes a pointer to a uint8_t array and writes the next unicode character's codepoint into codepoint.
        // The -1 means it reads up to 4 bytes (the max length of a utf-8 character).
        utf8proc_iterate(pDecomposedString + offset, -1, &codepoint);

        // Null terminator, end of string
        if (codepoint == 0) {
            break;
        }

        const utf8proc_int32_t codepointCopy = codepoint;

        utf8proc_uint8_t character;
        // This function takes a codepoint and puts the encoded utf-8 character into "character". It returns the bytes written.
        auto charSize = (size_t) utf8proc_encode_char(codepointCopy, &character);

        // I had been having some problems with trailing random characters (random unicode), but this seemed to fix it.
        // Could that have been related to the error?
        std::string realChar = std::string((const char*) &character).substr(0, charSize);

        // God knows why this is needed, but the above function call seems to somehow alter codepoint
        // Could be to do with the error?
        codepoint = codepointCopy;

        // Increments offset so the next character now would be read
        offset += charSize;

        // The actual useful part of the function: gets the category of the codepoint, and if it is Mark, Nonspacing (and not an iota subscript),
        // does not add it to the rebuilt string
        if ((utf8proc_category(codepoint) == UTF8PROC_CATEGORY_MN) && (codepoint != 0x0345)) {
            continue;
        }

        rebuiltString += realChar;
    }

    // Returns the composed form of the rebuilt string
    return calculateUnicodeNormalization(rebuiltString, "NFC");
}

Вы можете проверить этот код, например, написав функцию main:

#include <iostream>

int main() {
    std::cout << removeAccents("ᾤκεον") << std::endl;
}

Иожидая результата "ῳκεον".

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

Любые ответы приветствуются, и, как всегда, если что-то не хватает, пожалуйста, прокомментируйте, чтобы я мог добавить это.

1 Ответ

0 голосов
/ 08 сентября 2018
utf8proc_uint8_t character;
// This function takes a codepoint and puts the encoded utf-8 character into "character". It returns the bytes written.
auto charSize = (size_t) utf8proc_encode_char(codepointCopy, &character);

Это записывает до 4 байтов в однобайтовую переменную character, тем самым разрушая ваш стек.

 std::string((const char*) &character).substr(0, charSize);

будет более эффективным и менее аварийным (&character не является строкой с нулевым символом в конце) как:

 std::string((const char*) &character, charSize);

Или даже лучше:

 rebuiltString.append((const char*) &character, charSize);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...