Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strncpy equivalent for std::string?

Is there an exact equivalent to strncpy in the C++ Standard Library? I mean a function, that copies a string from one buffer to another until it hits the terminating 0? For instance when I have to parse strings from an unsafe source, such as TCP packets, so I'm able to perform checks in length while coping the data.

I already searched a lot regarding this topic and I also found some interesting topics, but all of those people were happy with std::string::assign, which is also able to take a size of characters to copy as a parameter. My problem with this function is, that it doesn't perform any checks if a terminating null was already hit - it takes the given size serious and copies the data just like memcpy would do it into the string's buffer. This way there is much more memory allocated and copied than it had to be done, if there were such a check while coping. 

That's the way I'm working around this problem currently, but there is some overhead I'd wish to avoid:

    // Get RVA of export name
    const ExportDirectory_t *pED = (const ExportDirectory_t*)rva2ptr(exportRVA);
    sSRA nameSra = rva2sra(pED->Name);

    // Copy it into my buffer
    char *szExportName = new char[nameSra.numBytesToSectionsEnd];
    strncpy(szExportName, 
            nameSra.pSection->pRawData->constPtr<char>(nameSra.offset),
            nameSra.numBytesToSectionsEnd);
    szExportName[nameSra.numBytesToSectionsEnd - 1] = 0;

    m_exportName = szExportName;
    delete [] szExportName;

This piece of code is part of my parser for PE-binaries (of the routine parsing the export table, to be exact). rva2sra converts a relative virtual address into a PE-section relative address. The ExportDirectory_t structure contains the RVA to the export name of the binary, which should be a zero-terminated string. But that doesn't always have to be the case - if someone would like it, it would be able to omit the terminating zero which would make my program run into memory which doesn't belong to the section, where it would finally crash (in the best case...).

It wouldn't be a big problem to implement such a function by myself, but I'd prefer it if there were a solution for this implemented in the C++ Standard Library.

like image 711
athre0z Avatar asked Jan 16 '12 19:01

athre0z


People also ask

What can I use instead of strcpy?

The strncpy() and strncat() functions are similar to the strcpy() and strcat() functions, but each has an additional size_t parameter n that limits the number of characters to be copied. These functions can be thought of as truncating copy and concatenation functions.

Is std::string the same as string?

There is no functionality difference between string and std::string because they're the same type.

What does strncpy () do?

The strncpy() function copies count characters of string2 to string1 . If count is less than or equal to the length of string2 , a null character (\0) is not appended to the copied string. If count is greater than the length of string2 , the string1 result is padded with null characters (\0) up to length count .

What can I use instead of strcpy in C++?

strcpy and friends are, at best, incredibly niche, and the correct replacement is memcpy .


2 Answers

If you know that the buffer you want to make a string out of has at least one NUL in it then you can just pass it to the constructor:

const char[] buffer = "hello\0there";

std::string s(buffer);

// s contains "hello"

If you're not sure, then you just have to search the string for the first null, and tell the constructor of string to make a copy of that much data:

int len_of_buffer = something;
const char* buffer = somethingelse;

const char* copyupto = std::find(buffer, buffer + len_of_buffer, 0); // find the first NUL

std::string s(buffer, copyupto);

// s now contains all the characters up to the first NUL from buffer, or if there
// was no NUL, it contains the entire contents of buffer

You can wrap the second version (which always works, even if there isn't a NUL in the buffer) up into a tidy little function:

std::string string_ncopy(const char* buffer, std::size_t buffer_size) {
    const char* copyupto = std::find(buffer, buffer + buffer_size, 0);

    return std::string(buffer, copyupto);
}

But one thing to note: if you hand the single-argument constructor a const char* by itself, it will go until it finds a NUL. It is important that you know there is at least one NUL in the buffer if you use the single-argument constructor of std::string.

Unfortunately (or fortunately), there is no built in perfect equivalent of strncpy for std::string.

like image 59
Seth Carnegie Avatar answered Sep 21 '22 02:09

Seth Carnegie


The std::string class in STL can contain null characters within the string ("xxx\0yyy" is a perfectly valid string of length 7). This means that it doesn't know anything about null termination (well almost, there are conversions from/to C strings). In other words, there's no alternative in the STL for strncpy.

There are a few ways to still accomplish your goal with a shorter code:

const char *ptr = nameSra.pSection->pRawData->constPtr<char>(nameSra.offset);
m_exportName.assign(ptr, strnlen(ptr, nameSra.numBytesToSectionsEnd));

or

const char *ptr = nameSra.pSection->pRawData->constPtr<char>(nameSra.offset);
m_exportName.reserve(nameSra.numBytesToSectionsEnd);
for (int i = 0; i < nameSra.numBytesToSectionsEnd && ptr[i]; i++) 
  m_exportName += ptr[i];
like image 41
Karel Petranek Avatar answered Sep 21 '22 02:09

Karel Petranek