Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to pass std::string to C style APIs?

Tags:

c++

c

string

It is well defined C++ to pass std::vector to C APIs that expect an output array like so because std::vector is contiguous:

std::vector<char> myArray(arraySize);
cStyleAPI(&myArray[0], arraySize);

Is it safe to pass std::string in the same manner to C APIs? Is there any guarantee in standard C++03 that std::string is contiguous and works in the same way as std::vector does in this situation?

like image 468
masrtis Avatar asked May 07 '13 17:05

masrtis


People also ask

Can you use std::string in C?

A std::string_view can refer to both a C++ string or a C-string. All that std::string_view needs to store is a pointer to the character sequence and a length. std::string_view provides the same API that std::string does, so it is a perfect match for C-style string literals.

Should you pass strings by reference C++?

OTOH, for C++98 it is best to pass by reference - less data gets copied around. Passing const or non const depend of whether you need to change the argument or not. Save this answer.

What is a difference between the std::string and C-style strings?

std::string is compatible with STL algorithms and other containers. C strings are not char * or const char * ; they are just null-terminated character arrays. Even string literals are just character arrays.


1 Answers

So, I know this has been answered already, but I saw your comment in Praetorian's answer:

It's an OpenGL driver bug that results in the return value for the maximum length string being broken. See https://forums.geforce.com/default/topic/531732/glgetactiveattrib-invalid/. glGetActiveAttrib won't try to write to the pointer returned by the new[] call with the 0 size allocation, but the string isn't null terminated. Then, later in the code, the non-null terminated string is copied into a std::string for storage, which results in a read buffer overflow. Very confusing to me too, and just checking here to see if std::string would make things easier to follow.

Uhm... forgive me but if this is your problem then all these solutions seem to be overly complicated. If the problem boils down to the fact that you get a 0 as the buffer size that you need (which means that you will end up with a string that's not NULL-terminated, since there's no space for the NULL terminator) then simply make sure a NULL terminator is always present:

int arraySize; 

/* assume arraySize is set to the length we need */
...

/* overallocate by 1 to add an explicit NULL terminator. Just in case. */
char *ptr = malloc(arraySize + 1);

if(ptr != NULL)
{
    /* zero out the chunk of memory we got */
    memset(ptr, 0, arraySize + 1);

    /* call OpenGL function */
    cStyleAPI(ptr, arraySize);

    /* behold, even if arraySize is 0 because of OpenGL, ptr is still NULL-terminated */
    assert(ptr[arraySize] == 0);

    /* use it */
    ...

    /* lose it */
    free(ptr);
}

This seems, to me, to be the simplest, sanest solution.

like image 164
Nik Bougalis Avatar answered Sep 22 '22 21:09

Nik Bougalis