Menu

#251 Overlapping memcpy in string::assign

5.2
open
5
2011-06-21
2011-06-20
Anonymous
No

string::assign(const char* s, size_t n) uses memcpy to copy new data into its buffer. This is invalid when the first argument points inside the string buffer. Example:

#include <string>

std::string s = "adasdsadasdsadsadasdasdsadsad";

void f(void) {
volatile int n = s.size();
s.assign((char*)s.data() + 0x10, n - 0x10);
}

int main(void) {
s.append(s);
f();
volatile int z = s.size();
return 0;
}

AFAIU, C++ standard allows such use.
Build this with g++ -O0 -g -fno-builtin and run under Valgrind.

Source and destination overlap in memcpy(0x5e240c0, 0x5e240d0, 42)
at 0x4C2C774: memcpy
by 0x4018C7: stlp_std::__char_traits_base<char, int>::copy(char*, char const*, unsigned long)
by 0x4014E1: stlp_std::basic_string<char, stlp_std::char_traits<char>, stlp_std::allocator<char> >::_M_assign(char const*, char const*)
by 0x4012DF: stlp_std::basic_string<char, stlp_std::char_traits<char>, stlp_std::allocator<char> >::assign(char const*, unsigned long)
by 0x400E20: f()
by 0x400E43: main

Tested with STLport-5.2.1.

Discussion

  • Petr Ovtchenkov

    Petr Ovtchenkov - 2011-06-21
    • assigned_to: nobody --> complement
     
  • Anonymous

    Anonymous - 2011-06-21

    Why not? The closest I found in the standard is

    21.4.1:

    6 References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated
    by the following uses of that basic_string object:
    — as an argument to any standard library function taking a reference to non-const basic_string as an
    argument.237
    — Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and
    rend.

    AFAIU this means that element references become invalid after calls to string methods (other then the listed ones). Passing it as an argument to any string methods, including mutating methods, is valid, otherwise a lot of common usages will be incorrect.

    21.4.6.3 basic_string::assign

    basic_string& assign(const charT* s, size_type n);
    8 Requires: s points to an array of at least n elements of charT.
    9 Throws: length_error if n > max_size().
    10 Effects: Replaces the string controlled by *this with a string of length n whose elements are a copy
    of those pointed to by s.
    11 Returns: *this.

    Nothing here.

     

Log in to post a comment.