views:

381

answers:

3

Buffer overrun problems are well known. Thus we were blessed with standard library functions such as wcscat_s(). And the kind folks at Microsoft have created similar safe string functions such as as StringCbCat().

But I have a problem where I need to search a bit of memory for a string. The Standard library function:

wcsstr( wchar_t* pMem, wchar_t* pStr )

seems great, but... Sometimes my memory contains garbage, sometimes strings. And when it is garbage I sometimes run off an allocated memory page, [=Access Violation]. I can write my own function yes. But my question is if there is any "standard" function to do safe string search such as:

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

Thanx

[EDIT] Thanks and kudos to Charles Bailey for a perfect answer to my question. Thanks to others for their efforts too.

And to those of you who doubted the saneness of my scenario: Yes of course it would be good to not ever have garbage in my memory. But I can imagine several scenarios where this situation could occur. In my particular case it is reverse-engineering, and the memory I am serching is in fact not "my memory", it belongs to another process which I cannot control.

(One other hypothetical scenario could be a tricky debugging situation where corrupted memory needs to be tracked down.)

+5  A: 

Probably not the answer you were looking for, but perhaps the best solution here would be to properly initialise your strings and pointers. If your memory contains garbage, why not do the decent thing and set

yourString[0] = '\0';

If it really is just an arbitrary bit of buffer, you might be better off using something like memcmp and slide the memory buffer's pointer along N characters (where N is the number of characters you're interested in minus the length of the string you're comparing). That might not be the most efficient implementation, but should be a fairly robust approach I should think.

[Edit] Your question intrigued me enough to do a little experimentation. Given that you seem to be looking for more C-styled answer, here's a little snippet of code I came up with to elaborate on my memcmp suggestion:

// 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;
}

That snippet compiled under Visual Studio 2008 as a Win32 console app. Gives me the following:

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

The FindStringInBuffer function is the bit you'll want and if you need to cope with wide characters, you'll need to do some conversion, but this should at least give you some ideas that you can proceed with. If you do come up with a wchar version, I'd be interested to see what the solution looks like (I've not dealt with them myself).

Jon Cage
+1 for the edited memcmp :)
Magnus Skog
+1  A: 

There is, alas, still no standard "safe" string library I'm aware of. BSD has strnstr for this, but it's not in the glibc, or Microsofts libc as far as I know. I don't know of any "good" choice for this, other than a roll your own.

For reference, the Microsoft safe string library is listed at http://msdn.microsoft.com/en-us/library/wd3wzwts(VS.80).aspx and given in more detail (with migration guides) at http://msdn.microsoft.com/en-us/library/bb288454.aspx.

Adam Wright
+2  A: 

Assuming that your pStr is null terminated and that uiSize is the number of wchar_t of readable memory at 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;
Charles Bailey
Perfect! Thanks!
Adam