StringData::StringData(const char *data, int len, StringDataMode mode) : m_data(NULL), _count(0), m_len(0) { m_hash = 0; assign(data, len, mode); TAINT_OBSERVER_REGISTER_MUTATED(this); }
void StringBuffer::absorb(StringBuffer &buf) { if (empty()) { TAINT_OBSERVER_REGISTER_ACCESSED(buf.getTaintDataRefConst()); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); StringData* str = m_str; m_str = buf.m_str; m_buffer = buf.m_buffer; m_len = buf.m_len; m_cap = buf.m_cap; buf.m_str = str; if (str) { buf.m_buffer = (char*)str->data(); buf.m_len = str->size(); buf.m_cap = str->capacity(); } else { buf.m_buffer = 0; buf.m_len = 0; buf.m_cap = 0; } buf.reset(); } else { // REGISTER_ACCESSED()/REGISTER_MUTATED() are called by append()/detach() append(buf.detach()); } }
CstrBuffer::CstrBuffer(const char *filename) : m_buffer(NULL), m_len(0) { struct stat sb; if (stat(filename, &sb) == 0) { if (sb.st_size > kMaxCap - 1) { std::ostringstream out; out << "file " << filename << " is too large"; throw StringBufferLimitException(kMaxCap, String(out.str().c_str())); } m_cap = sb.st_size; m_buffer = (char *)Util::safe_malloc(m_cap + 1); int fd = ::open(filename, O_RDONLY); if (fd != -1) { while (m_len < m_cap) { int buffer_size = m_cap - m_len; int len = ::read(fd, m_buffer + m_len, buffer_size); if (len == -1 && errno == EINTR) continue; if (len <= 0) break; m_len += len; } ::close(fd); } } TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); }
StringBuffer::StringBuffer(int initialSize /* = 63 */) : m_initialCap(initialSize), m_maxBytes(kDefaultOutputLimit), m_cap(initialSize), m_len(0) { ASSERT(initialSize > 0); m_str = NEW(StringData)(initialSize); m_buffer = (char *)m_str->data(); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); }
StringData::StringData(const char *data, StringDataMode mode /* = AttachLiteral */) : m_data(NULL), _count(0), m_len(0) { m_hash = 0; assign(data, mode); TAINT_OBSERVER_REGISTER_MUTATED(this); }
StringBuffer::StringBuffer(int initialSize /* = 63 */) : m_initialCap(initialSize), m_maxBytes(kDefaultOutputLimit), m_len(0) { assert(initialSize > 0); m_str = NEW(StringData)(initialSize); MutableSlice s = m_str->mutableSlice(); m_buffer = s.ptr; m_cap = s.len; TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); }
HOT_FUNC StringData::StringData(SharedVariant *shared) : _count(0) { ASSERT(shared); shared->incRef(); m_hash = 0; m_len = shared->stringLength(); m_cdata = shared->stringData(); m_big.shared = shared; m_big.cap = m_len | IsShared; TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, rawdata()); }
StringData::StringData(SharedVariant *shared) : m_data(NULL), _count(0), m_len(0) { m_hash = 0; ASSERT(shared); shared->incRef(); m_shared = shared; m_data = m_shared->stringData(); m_len = m_shared->stringLength() | IsShared; ASSERT(m_data); TAINT_OBSERVER_REGISTER_MUTATED(this); }
void StringData::initLiteral(const char* data, int len) { if (uint32_t(len) > MaxSize) { throw InvalidArgumentException("len>=2^30", len); } // Do not copy literals, this StringData can have a shorter lifetime than // the literal, and the client can count on this->data() giving back // the literal ptr with the longer lifetime. Sketchy! m_hash = 0; _count = 0; m_len = len; m_cdata = data; m_big.cap = len | IsLiteral; ASSERT(checkSane()); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, rawdata()); }
void StringData::initAttachDeprecated(const char* data, int len) { if (uint32_t(len) > MaxSize) { throw InvalidArgumentException("len>=2^30", len); } // Don't copy small strings here either because the caller sometimes // assumes he can mess with data while this string is still alive, // and we want to free it eagerly. Sketchy! m_hash = 0; _count = 0; m_len = len; m_cdata = data; m_big.cap = len | IsMalloc; ASSERT(checkSane()); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, rawdata()); }
void StringData::append(const char *s, int len) { if (len == 0) return; if (len < 0 || (len & IsMask)) { throw InvalidArgumentException("len: %d", len); } ASSERT(!isStatic()); // never mess around with static strings! if (!isMalloced()) { int newlen; m_data = string_concat(data(), size(), s, len, newlen); if (isShared()) { m_shared->decRef(); } m_len = newlen; m_hash = 0; } else if (m_data == s) { int newlen; char *newdata = string_concat(data(), size(), s, len, newlen); releaseData(); m_data = newdata; m_len = newlen; } else { int dataLen = size(); ASSERT((m_data > s && m_data - s > len) || (m_data < s && s - m_data > dataLen)); // no overlapping m_len = len + dataLen; m_data = (const char*)realloc((void*)m_data, m_len + 1); memcpy((void*)(m_data + dataLen), s, len); ((char*)m_data)[m_len] = '\0'; m_hash = 0; } if (m_len & IsMask) { int len = m_len; m_len &= ~IsMask; releaseData(); m_data = NULL; throw FatalErrorException(0, "String length exceeded 2^29 - 1: %d", len); } TAINT_OBSERVER_REGISTER_MUTATED(this); }
void StringBuffer::absorb(StringBuffer &buf) { if (empty()) { TAINT_OBSERVER_REGISTER_ACCESSED(buf.getTaintDataRefConst()); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data); char *buffer = m_buffer; int size = m_size; m_buffer = buf.m_buffer; m_size = buf.m_size; m_pos = buf.m_pos; buf.m_buffer = buffer; buf.m_size = size; buf.reset(); } else { append(buf.detach()); } }
StringBuffer::StringBuffer(const char *filename) : m_buffer(NULL), m_initialSize(1024), m_maxBytes(0), m_size(0), m_pos(0) { struct stat sb; if (stat(filename, &sb) == 0) { m_size = sb.st_size; m_buffer = (char *)Util::safe_malloc(m_size + 1); int fd = ::open(filename, O_RDONLY); if (fd != -1) { while (m_pos < m_size) { int buffer_size = m_size - m_pos; int len = ::read(fd, m_buffer + m_pos, buffer_size); if (len == -1 && errno == EINTR) continue; if (len <= 0) break; m_pos += len; } ::close(fd); } } TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); }
HOT_FUNC void StringData::initAttach(const char* data, int len) { if (uint32_t(len) > MaxSize) { throw InvalidArgumentException("len>=2^30", len); } m_hash = 0; _count = 0; if (uint32_t(len) <= MaxSmallSize) { memcpy(m_small, data, len); m_len = len; m_data = m_small; m_small[len] = 0; m_small[MaxSmallSize] = 0; free((void*)data); } else { m_len = len; m_cdata = data; m_big.cap = len | IsMalloc; } ASSERT(checkSane()); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, rawdata()); }
CstrBuffer::CstrBuffer(int cap) : m_buffer((char*)Util::safe_malloc(cap + 1)), m_len(0), m_cap(cap) { ASSERT(unsigned(cap) <= kMaxCap); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); }
StringBuffer::StringBuffer(int initialSize /* = 1024 */) : m_initialSize(initialSize), m_maxBytes(0), m_size(initialSize), m_pos(0) { ASSERT(initialSize > 0); m_buffer = (char *)Util::safe_malloc(initialSize + 1); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); }
StringBuffer::StringBuffer(char *data, int len) : m_buffer(data), m_initialSize(1024), m_maxBytes(0), m_size(len), m_pos(len) { TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); }
void StringData::append(const char *s, int len) { ASSERT(!isStatic()); // never mess around with static strings! if (len == 0) return; if (UNLIKELY(uint32_t(len) > MaxSize)) { throw InvalidArgumentException("len>=2^30", len); } if (UNLIKELY(len + m_len > MaxSize)) { throw FatalErrorException(0, "String length exceeded 2^30 - 1: %u", len + m_len); } int newlen; // TODO: t1122987: in any of the cases below where we need a bigger buffer, // we can probably assume we're in a concat-loop and pick a good buffer // size to avoid O(N^2) copying cost. if (isShared() || isLiteral()) { // buffer is immutable, don't modify it. // We are mutating, so we don't need to repropagate our own taint StringSlice r = slice(); char* newdata = string_concat(r.ptr, r.len, s, len, newlen); if (isShared()) m_big.shared->decRef(); m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } else if (rawdata() == s) { // appending ourself to ourself, be conservative. // We are mutating, so we don't need to repropagate our own taint StringSlice r = slice(); char *newdata = string_concat(r.ptr, r.len, s, len, newlen); releaseData(); m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } else if (isSmall()) { // we're currently small but might not be after append. // We are mutating, so we don't need to repropagate our own taint int oldlen = m_len; newlen = oldlen + len; if (unsigned(newlen) <= MaxSmallSize) { // win. memcpy(&m_small[oldlen], s, len); m_small[newlen] = 0; m_small[MaxSmallSize] = 0; m_len = newlen; m_data = m_small; m_hash = 0; } else { // small->big string transition. char *newdata = string_concat(m_small, oldlen, s, len, newlen); m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } } else { // generic "big string concat" path. realloc buffer. int oldlen = m_len; char* oldp = m_data; ASSERT((oldp > s && oldp - s > len) || (oldp < s && s - oldp > oldlen)); // no overlapping newlen = oldlen + len; char* newdata = (char*) realloc(oldp, newlen + 1); memcpy(newdata + oldlen, s, len); newdata[newlen] = 0; m_len = newlen; m_data = newdata; m_big.cap = newlen | IsMalloc; m_hash = 0; } ASSERT(uint32_t(newlen) <= MaxSize); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, rawdata()); ASSERT(checkSane()); }
void StringBuffer::append(CStrRef s) { append(s.data(), s.size()); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data); }