Fixes: #10938 Keep allocated memory when rhs fits Use case: Appending to a String with pre-allocated memory (e.g. from `reserve()`) No need to move 0-termination char in String::move Simplify calls to String::copy A lot of the same checks were done before calling `copy()` which should be done in the `copy()` function itself. String::copy() Should not copy more than given length Fix potential out of range in String::concat There is no prerequisite the given array has to be a 0-terminated char array. So we should only copy the length that has been given. The `setLen()` function will make sure the internal string is 0-terminated. So no need to dangerously assume there will be 1 more byte to copy Allow String::concat(const String &s) with s.buffer() == nullptr When constructing a String object, the internal buffer is a nullptr. However concatenating this to another String would return `false` while this is perfectly fine to do.
This commit is contained in:
parent
6fb55a7f68
commit
5488d5d23f
1 changed files with 21 additions and 33 deletions
|
|
@ -226,11 +226,11 @@ bool String::changeBuffer(unsigned int maxStrLen) {
|
||||||
/*********************************************/
|
/*********************************************/
|
||||||
|
|
||||||
String &String::copy(const char *cstr, unsigned int length) {
|
String &String::copy(const char *cstr, unsigned int length) {
|
||||||
if (!reserve(length)) {
|
if (cstr == nullptr || !reserve(length)) {
|
||||||
invalidate();
|
invalidate();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
memmove(wbuffer(), cstr, length + 1);
|
memmove(wbuffer(), cstr, length);
|
||||||
setLen(length);
|
setLen(length);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -239,17 +239,20 @@ String &String::copy(const char *cstr, unsigned int length) {
|
||||||
void String::move(String &rhs) {
|
void String::move(String &rhs) {
|
||||||
if (buffer()) {
|
if (buffer()) {
|
||||||
if (capacity() >= rhs.len()) {
|
if (capacity() >= rhs.len()) {
|
||||||
memmove(wbuffer(), rhs.buffer(), rhs.length() + 1);
|
// Use case: When 'reserve()' was called and the first
|
||||||
|
// assignment/append is the return value of a function.
|
||||||
|
if (rhs.len() && rhs.buffer()) {
|
||||||
|
memmove(wbuffer(), rhs.buffer(), rhs.length());
|
||||||
|
}
|
||||||
setLen(rhs.len());
|
setLen(rhs.len());
|
||||||
rhs.invalidate();
|
rhs.invalidate();
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
if (!isSSO()) {
|
if (!isSSO()) {
|
||||||
free(wbuffer());
|
free(wbuffer());
|
||||||
setBuffer(nullptr);
|
setBuffer(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (rhs.isSSO()) {
|
if (rhs.isSSO()) {
|
||||||
setSSO(true);
|
setSSO(true);
|
||||||
memmove(sso.buff, rhs.sso.buff, sizeof(sso.buff));
|
memmove(sso.buff, rhs.sso.buff, sizeof(sso.buff));
|
||||||
|
|
@ -259,10 +262,7 @@ void String::move(String &rhs) {
|
||||||
}
|
}
|
||||||
setCapacity(rhs.capacity());
|
setCapacity(rhs.capacity());
|
||||||
setLen(rhs.len());
|
setLen(rhs.len());
|
||||||
rhs.setSSO(false);
|
rhs.init();
|
||||||
rhs.setCapacity(0);
|
|
||||||
rhs.setBuffer(nullptr);
|
|
||||||
rhs.setLen(0);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -270,12 +270,7 @@ String &String::operator=(const String &rhs) {
|
||||||
if (this == &rhs) {
|
if (this == &rhs) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
if (rhs.buffer()) {
|
return copy(rhs.buffer(), rhs.len());
|
||||||
copy(rhs.buffer(), rhs.len());
|
|
||||||
} else {
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||||
|
|
@ -295,12 +290,7 @@ String &String::operator=(StringSumHelper &&rval) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String &String::operator=(const char *cstr) {
|
String &String::operator=(const char *cstr) {
|
||||||
if (cstr) {
|
return copy(cstr, strlen(cstr));
|
||||||
copy(cstr, strlen(cstr));
|
|
||||||
} else {
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************/
|
/*********************************************/
|
||||||
|
|
@ -311,23 +301,21 @@ bool String::concat(const String &s) {
|
||||||
// Special case if we're concatting ourself (s += s;) since we may end up
|
// Special case if we're concatting ourself (s += s;) since we may end up
|
||||||
// realloc'ing the buffer and moving s.buffer in the method called
|
// realloc'ing the buffer and moving s.buffer in the method called
|
||||||
if (&s == this) {
|
if (&s == this) {
|
||||||
unsigned int newlen = 2 * len();
|
|
||||||
if (!s.buffer()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (s.len() == 0) {
|
if (s.len() == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (!s.buffer()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unsigned int newlen = 2 * len();
|
||||||
if (!reserve(newlen)) {
|
if (!reserve(newlen)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memmove(wbuffer() + len(), buffer(), len());
|
memmove(wbuffer() + len(), buffer(), len());
|
||||||
setLen(newlen);
|
setLen(newlen);
|
||||||
wbuffer()[len()] = 0;
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
return concat(s.buffer(), s.len());
|
|
||||||
}
|
}
|
||||||
|
return concat(s.buffer(), s.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::concat(const char *cstr, unsigned int length) {
|
bool String::concat(const char *cstr, unsigned int length) {
|
||||||
|
|
@ -343,10 +331,10 @@ bool String::concat(const char *cstr, unsigned int length) {
|
||||||
}
|
}
|
||||||
if (cstr >= wbuffer() && cstr < wbuffer() + len()) {
|
if (cstr >= wbuffer() && cstr < wbuffer() + len()) {
|
||||||
// compatible with SSO in ram #6155 (case "x += x.c_str()")
|
// compatible with SSO in ram #6155 (case "x += x.c_str()")
|
||||||
memmove(wbuffer() + len(), cstr, length + 1);
|
memmove(wbuffer() + len(), cstr, length);
|
||||||
} else {
|
} else {
|
||||||
// compatible with source in flash #6367
|
// compatible with source in flash #6367
|
||||||
memcpy_P(wbuffer() + len(), cstr, length + 1);
|
memcpy_P(wbuffer() + len(), cstr, length);
|
||||||
}
|
}
|
||||||
setLen(newlen);
|
setLen(newlen);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue