C ++ (действительно) Безопасный стандартный поиск строк? - PullRequest
1 голос
/ 27 мая 2009

Проблемы переполнения буфера хорошо известны. Таким образом, мы были благословлены стандартными библиотечными функциями, такими как wcscat_s (). И добрые люди в Microsoft создали подобные безопасные строковые функции, такие как StringCbCat ().

Но у меня есть проблема, когда мне нужно найти бит памяти для строки. Функция стандартной библиотеки:

wcsstr( wchar_t* pMem, wchar_t* pStr ) 

кажется отличным, но ... Иногда моя память содержит мусор, иногда строки. И когда это мусор, я иногда запускаю выделенную страницу памяти, [= Нарушение прав доступа]. Я могу написать свою собственную функцию да. Но у меня вопрос, есть ли какая-нибудь «стандартная» функция для безопасного поиска строк, например:

"wcsstr_s( wchar_t* pMem, size_t uiSize, wchar_t* pStr )" ?

Thanx

[EDIT] Спасибо и спасибо Чарльзу Бэйли за прекрасный ответ на мой вопрос. Спасибо другим за их усилия.

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

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

Ответы [ 3 ]

6 голосов
/ 27 мая 2009

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

yourString[0] = '\0';

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

[Редактировать] Ваш вопрос заинтриговал меня достаточно, чтобы немного поэкспериментировать. Учитывая, что вы, похоже, ищете более ответ в стиле C, вот небольшой фрагмент кода, который я придумал, чтобы уточнить мое предложение memcmp:

// SearchingMemoryForStrings.cpp : Defines the entry point for a win32 consol application
// Purpose : Demonstrates a way to search a section of memory for a particular string
//

#include <stdio.h>
#include <string.h>

#define VALUE_NOT_FOUND (-1)

int FindStringInBuffer( const char* pMemBuffer, const size_t& bufferSizeInBytes, const char* pStrToFind )
{
    int stringFound = VALUE_NOT_FOUND; // Return value which will be >= 0 if we find the string we're after
    const char* pMemToMatch = NULL; // An offset pointer to part of 'pMemBuffer' which we'll feed to memcmp to find 'pStrToFind'

    // Set up some constants we'll use while searching
    size_t lenOfStrToFind = strlen( pStrToFind );
    size_t lastSearchablePosition = bufferSizeInBytes - lenOfStrToFind;

    // Search the memory buffer, shifting one character at a time for 'pStrToFind'
    for( size_t i = 0; i <= lastSearchablePosition; i++ ) {
        pMemToMatch = &pMemBuffer[i];
        if( memcmp(pMemToMatch, pStrToFind, lenOfStrToFind) == 0 ) {
            // We found the string we're looking for
            stringFound = i;
            break;
        }
    }

    return stringFound;
}

void ReportResult( int returnVal, const char* stringToFind )
{
    if( returnVal == VALUE_NOT_FOUND ) {
        // Fail!
        printf("Error, failed to find '%s' - search function returned %d\n", stringToFind, returnVal );
    }
    else {
        // Win!
        printf("Success, found '%s' at index %d\n", stringToFind, returnVal );
    }
}

void FindAndReport( const char* pMemBuffer, const size_t& bufferSizeInBytes, const char* pStrToFind )
{
    int result = FindStringInBuffer( pMemBuffer, bufferSizeInBytes, pStrToFind );
    ReportResult( result, pStrToFind );
}

int main( int argc, char* argv[] )
{
    const int SIZE_OF_BUFFER = 1024; // Some aribitrary buffer size
    char some_memory[SIZE_OF_BUFFER]; // The buffer of randomly assigned memory to look for our string
    const char* stringToFind = "This test should pass";
    const char* stringYouWontFind = "This test should fail";

    FindAndReport( some_memory, SIZE_OF_BUFFER, stringYouWontFind ); // Should fail gracefully

    // Set the end of the buffer to the string we're looking for
    memcpy( &some_memory[SIZE_OF_BUFFER-strlen(stringToFind)], stringToFind, strlen(stringToFind) );

    FindAndReport( some_memory, SIZE_OF_BUFFER, stringToFind ); // Should succeed this time and report an index of 1003

    // Try adding at some arbitrary position
    memcpy( &some_memory[100], stringToFind, strlen(stringToFind) );

    FindAndReport( some_memory, SIZE_OF_BUFFER, stringToFind ); // Should still succeed but report the offset as 100

    FindAndReport( some_memory, SIZE_OF_BUFFER, stringYouWontFind ); // Should still fail


    return 0;
}

Этот фрагмент скомпилирован под Visual Studio 2008 как консольное приложение Win32. Дает мне следующее:

Error, failed to find 'This test should fail' - search function returned -1
Success, found 'This test should pass' at index 1003
Success, found 'This test should pass' at index 100
Error, failed to find 'This test should fail' - search function returned -1

Функция FindStringInBuffer - это бит, который вам нужен, и если вам нужно справиться с широкими символами, вам нужно будет выполнить какое-то преобразование, но это должно по крайней мере дать вам некоторые идеи, с которыми вы можете продолжить. Если вы придумали версию wchar, мне было бы интересно посмотреть, как выглядит решение (я сам с ними не сталкивался).

2 голосов
/ 27 мая 2009

Предполагается, что ваш pStr имеет нулевое значение и uiSize - это число wchar_t читаемой памяти в pMem:

wchar_t* pSubStr = std::search( pMem, pMem + uiSize, pStr, pStr + std::wcslen( pStr ) );

// Optionally, change to the 'conventional' strstr return value
if( pSubStr == pMem + uiSize)
    pSubStr = 0;
2 голосов
/ 27 мая 2009

У меня, к сожалению, до сих пор нет стандартной "безопасной" библиотеки строк. В BSD для этого есть strnstr, но, насколько я знаю, его нет ни в glibc, ни в libs Microsoft. Я не знаю ни одного «хорошего» выбора для этого, кроме собственного ролла.

Для справки, библиотека безопасных строк Microsoft указана в http://msdn.microsoft.com/en-us/library/wd3wzwts(VS.80).aspx и дана более подробно (с руководствами по миграции) в http://msdn.microsoft.com/en-us/library/bb288454.aspx.

...