@ -252,21 +252,21 @@ class AddrMap {
public:
AddrMap() : size_(0), allocated_(0), obj_(nullptr) {}
~AddrMap() { base_internal::LowLevelAlloc::Free(obj_); }
in t Size() const { return size_; }
ObjFile *At(in t i) { return &obj_[i]; }
size_ t Size() const { return size_; }
ObjFile *At(size_ t i) { return &obj_[i]; }
ObjFile *Add();
void Clear();
private:
in t size_; // count of valid elements (< = allocated_)
in t allocated_; // count of allocated elements
ObjFile *obj_; // array of allocated_ elements
size_ t size_; // count of valid elements (< = allocated_)
size_ t allocated_; // count of allocated elements
ObjFile *obj_; // array of allocated_ elements
AddrMap(const AddrMap & ) = delete;
AddrMap & operator=(const AddrMap & ) = delete;
};
void AddrMap::Clear() {
for (in t i = 0; i != size_; i++) {
for (size_ t i = 0; i != size_; i++) {
At(i)->~ObjFile();
}
size_ = 0;
@ -274,7 +274,7 @@ void AddrMap::Clear() {
ObjFile *AddrMap::Add() {
if (size_ == allocated_) {
in t new_allocated = allocated_ * 2 + 50;
size_ t new_allocated = allocated_ * 2 + 50;
ObjFile *new_obj_ =
static_cast< ObjFile * > (base_internal::LowLevelAlloc::AllocWithArena(
new_allocated * sizeof(*new_obj_), SigSafeArena()));
@ -300,7 +300,7 @@ class Symbolizer {
private:
char *CopyString(const char *s) {
in t len = strlen(s);
size_ t len = strlen(s);
char *dst = static_cast< char * > (
base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
ABSL_RAW_CHECK(dst != nullptr, "out of memory");
@ -321,8 +321,8 @@ class Symbolizer {
FindSymbolResult GetSymbolFromObjectFile(const ObjFile & obj,
const void *const pc,
const ptrdiff_t relocation,
char *out, in t out_size,
char *tmp_buf, in t tmp_buf_size);
char *out, size_ t out_size,
char *tmp_buf, size_ t tmp_buf_size);
const char *GetUncachedSymbol(const void *pc);
enum {
@ -353,11 +353,11 @@ static std::atomic<Symbolizer *> g_cached_symbolizer;
} // namespace
static in t SymbolizerSize() {
static size_ t SymbolizerSize() {
#if defined(__wasm__) || defined(__asmjs__)
int pagesize = getpagesize( );
auto pagesize = static_cast< size_t > (getpagesize() );
#else
int pagesize = sysconf(_SC_PAGESIZE );
auto pagesize = static_cast< size_t > (sysconf(_SC_PAGESIZE) );
#endif
return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize;
}
@ -429,7 +429,7 @@ static ssize_t ReadPersistent(int fd, void *buf, size_t count) {
if (len == 0) { // Reached EOF.
break;
}
num_bytes += len;
num_bytes += static_cast< size_t > ( len) ;
}
SAFE_ASSERT(num_bytes < = count);
return static_cast< ssize_t > (num_bytes);
@ -478,36 +478,37 @@ static int FileGetElfType(const int fd) {
// inlined.
static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(
const int fd, ElfW(Half) sh_num, const off_t sh_offset, ElfW(Word) type,
ElfW(Shdr) * out, char *tmp_buf, in t tmp_buf_size) {
ElfW(Shdr) * out, char *tmp_buf, size_ t tmp_buf_size) {
ElfW(Shdr) *buf = reinterpret_cast< ElfW ( Shdr ) * > (tmp_buf);
const in t buf_entries = tmp_buf_size / sizeof(buf[0]);
const in t buf_bytes = buf_entries * sizeof(buf[0]);
const size_ t buf_entries = tmp_buf_size / sizeof(buf[0]);
const size_ t buf_bytes = buf_entries * sizeof(buf[0]);
for (int i = 0; i < sh_num ; ) {
const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
const ssize_t num_bytes_to_read =
for (size_t i = 0; static_cast< int > (i) < sh_num ; ) {
const size_t num_bytes_left =
(static_cast< size_t > (sh_num) - i) * sizeof(buf[0]);
const size_t num_bytes_to_read =
(buf_bytes > num_bytes_left) ? num_bytes_left : buf_bytes;
const off_t offset = sh_offset + i * sizeof(buf[0]);
const off_t offset = sh_offset + static_cast< off_t > ( i * sizeof(buf[0]) );
const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read, offset);
if (len < 0 ) {
ABSL_RAW_LOG(
WARNING,
"Reading %zd bytes from offset %ju returned %zd which is negative.",
"Reading %zu bytes from offset %ju returned %zd which is negative.",
num_bytes_to_read, static_cast< intmax_t > (offset), len);
return false;
}
if (len % sizeof(buf[0]) != 0) {
if (static_cast< size_t > ( len) % sizeof(buf[0]) != 0) {
ABSL_RAW_LOG(
WARNING,
"Reading %zd bytes from offset %jd returned %zd which is not a "
"Reading %zu bytes from offset %jd returned %zd which is not a "
"multiple of %zu.",
num_bytes_to_read, static_cast< intmax_t > (offset), len,
sizeof(buf[0]));
return false;
}
const ss ize_t num_headers_in_buf = l en / sizeof(buf[0]);
const size_t num_headers_in_buf = static_cast< siz e_t > (len) / sizeof(buf[0]);
SAFE_ASSERT(num_headers_in_buf < = buf_entries);
for (in t j = 0; j < num_headers_in_buf ; + + j ) {
for (size_ t j = 0; j < num_headers_in_buf ; + + j ) {
if (buf[j].sh_type == type) {
*out = buf[j];
return true;
@ -531,8 +532,8 @@ bool ForEachSection(int fd,
}
ElfW(Shdr) shstrtab;
off_t shstrtab_offset =
(elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx) ;
off_t shstrtab_offset = static_cast< off_t > (elf_header.e_shoff) +
elf_header.e_shentsize * elf_header.e_shstrndx ;
if (!ReadFromOffsetExact(fd, & shstrtab, sizeof(shstrtab), shstrtab_offset)) {
return false;
}
@ -540,22 +541,23 @@ bool ForEachSection(int fd,
for (int i = 0; i < elf_header.e_shnum ; + + i ) {
ElfW(Shdr) out;
off_t section_header_offset =
(elf_header.e_shoff + elf_header.e_shentsize * i) ;
static_cast< off_t > (elf_header.e_shoff) + elf_header.e_shentsize * i;
if (!ReadFromOffsetExact(fd, & out, sizeof(out), section_header_offset)) {
return false;
}
off_t name_offset = shstrtab.sh_offset + out.sh_name;
off_t name_offset = static_cast< off_t > (s hstrtab.sh_offset) + out.sh_name;
char header_name[kMaxSectionNameLen];
ssize_t n_read =
ReadFromOffset(fd, & header_name, kMaxSectionNameLen, name_offset);
if (n_read == -1) {
if (n_read < 0 ) {
return false;
} else if (n_read > kMaxSectionNameLen) {
// Long read?
return false;
}
absl::string_view name(header_name, strnlen(header_name, n_read));
absl::string_view name(header_name,
strnlen(header_name, static_cast< size_t > (n_read)));
if (!callback(name, out)) {
break;
}
@ -582,19 +584,19 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
}
ElfW(Shdr) shstrtab;
off_t shstrtab_offset =
(elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx) ;
off_t shstrtab_offset = static_cast< off_t > (elf_header.e_shoff) +
elf_header.e_shentsize * elf_header.e_shstrndx ;
if (!ReadFromOffsetExact(fd, & shstrtab, sizeof(shstrtab), shstrtab_offset)) {
return false;
}
for (int i = 0; i < elf_header.e_shnum ; + + i ) {
off_t section_header_offset =
(elf_header.e_shoff + elf_header.e_shentsize * i) ;
static_cast< off_t > (elf_header.e_shoff) + elf_header.e_shentsize * i;
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
return false;
}
off_t name_offset = shstrtab.sh_offset + out->sh_name;
off_t name_offset = static_cast< off_t > (s hstrtab.sh_offset) + out->sh_name;
ssize_t n_read = ReadFromOffset(fd, & header_name, name_len, name_offset);
if (n_read < 0 ) {
return false;
@ -652,10 +654,10 @@ static bool InSection(const void *address, const ElfW(Shdr) * section) {
}
static const char *ComputeOffset(const char *base, ptrdiff_t offset) {
// Note: cast to u intptr_t to avoid undefined behavior when base evaluates to
// Note: cast to intptr_t to avoid undefined behavior when base evaluates to
// zero and offset is non-zero.
return reinterpret_cast< const char * > (
reinterpret_cast< uintptr_t > (base) + offset);
return reinterpret_cast< const char * > (reinterpret_cast< intptr_t > (base) +
offset);
}
// Read a symbol table and look for the symbol containing the
@ -668,18 +670,18 @@ static const char *ComputeOffset(const char *base, ptrdiff_t offset) {
// To keep stack consumption low, we would like this function to not get
// inlined.
static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
const void *const pc, const int fd, char *out, in t out_size,
const void *const pc, const int fd, char *out, size_ t out_size,
ptrdiff_t relocation, const ElfW(Shdr) * strtab, const ElfW(Shdr) * symtab,
const ElfW(Shdr) * opd, char *tmp_buf, in t tmp_buf_size) {
const ElfW(Shdr) * opd, char *tmp_buf, size_ t tmp_buf_size) {
if (symtab == nullptr) {
return SYMBOL_NOT_FOUND;
}
// Read multiple symbols at once to save read() calls.
ElfW(Sym) *buf = reinterpret_cast< ElfW ( Sym ) * > (tmp_buf);
const in t buf_entries = tmp_buf_size / sizeof(buf[0]);
const size_ t buf_entries = tmp_buf_size / sizeof(buf[0]);
const in t num_symbols = symtab->sh_size / symtab->sh_entsize;
const size_ t num_symbols = symtab->sh_size / symtab->sh_entsize;
// On platforms using an .opd section (PowerPC & IA64), a function symbol
// has the address of a function descriptor, which contains the real
@ -694,17 +696,19 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
ElfW(Sym) best_match;
SafeMemZero(& best_match, sizeof(best_match));
bool found_match = false;
for (int i = 0; i < num_symbols ; ) {
off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
const int num_remaining_symbols = num_symbols - i;
const int entries_in_chunk = std::min(num_remaining_symbols, buf_entries);
const int bytes_in_chunk = entries_in_chunk * sizeof(buf[0]);
for (size_t i = 0; i < num_symbols ; ) {
off_t offset =
static_cast< off_t > (symtab->sh_offset + i * symtab->sh_entsize);
const size_t num_remaining_symbols = num_symbols - i;
const size_t entries_in_chunk =
std::min(num_remaining_symbols, buf_entries);
const size_t bytes_in_chunk = entries_in_chunk * sizeof(buf[0]);
const ssize_t len = ReadFromOffset(fd, buf, bytes_in_chunk, offset);
SAFE_ASSERT(len >= 0);
SAFE_ASSERT(len % sizeof(buf[0]) == 0);
const ss ize_t num_symbols_in_buf = l en / sizeof(buf[0]);
SAFE_ASSERT(static_cast< size_t > ( len) % sizeof(buf[0]) == 0);
const size_t num_symbols_in_buf = static_cast< siz e_t > (len) / sizeof(buf[0]);
SAFE_ASSERT(num_symbols_in_buf < = entries_in_chunk);
for (in t j = 0; j < num_symbols_in_buf ; + + j ) {
for (size_ t j = 0; j < num_symbols_in_buf ; + + j ) {
const ElfW(Sym) & symbol = buf[j];
// For a DSO, a symbol address is relocated by the loading address.
@ -721,7 +725,7 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
// about what encoding is being used; we just want the real start address
// of the function.
start_address = reinterpret_cast< const char * > (
reinterpret_cast< uintptr_t > (start_address) & ~1);
reinterpret_cast< uintptr_t > (start_address) & ~1u );
#endif
if (deref_function_descriptor_pointer & &
@ -734,7 +738,8 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
// If pc is inside the .opd section, it points to a function descriptor.
const size_t size = pc_in_opd ? kFunctionDescriptorSize : symbol.st_size;
const void *const end_address = ComputeOffset(start_address, size);
const void *const end_address =
ComputeOffset(start_address, static_cast< ptrdiff_t > (size));
if (symbol.st_value != 0 & & // Skip null value symbols.
symbol.st_shndx != 0 & & // Skip undefined symbols.
#ifdef STT_TLS
@ -752,16 +757,19 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
}
if (found_match) {
const size_t off = strtab->sh_offset + best_match.st_name;
const off_t off =
static_cast< off_t > (strtab->sh_offset) + best_match.st_name;
const ssize_t n_read = ReadFromOffset(fd, out, out_size, off);
if (n_read < = 0) {
// This should never happen.
ABSL_RAW_LOG(WARNING,
"Unable to read from fd %d at offset %zu: n_read = %zd", fd,
off, n_read);
ABSL_RAW_LOG(
WARNING,
"Unable to read from fd %d at offset %" PRId64 ": n_read = %zd", fd,
off, n_read);
return SYMBOL_NOT_FOUND;
}
ABSL_RAW_CHECK(n_read < = out_size, "ReadFromOffset read too much data.");
ABSL_RAW_CHECK(static_cast< size_t > (n_read) < = out_size,
"ReadFromOffset read too much data.");
// strtab->sh_offset points into .strtab-like section that contains
// NUL-terminated strings: '\0foo\0barbaz\0...".
@ -769,7 +777,7 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
// sh_offset+st_name points to the start of symbol name, but we don't know
// how long the symbol is, so we try to read as much as we have space for,
// and usually over-read (i.e. there is a NUL somewhere before n_read).
if (memchr(out, '\0', n_read) == nullptr) {
if (memchr(out, '\0', static_cast< size_t > ( n_read) ) == nullptr) {
// Either out_size was too small (n_read == out_size and no NUL), or
// we tried to read past the EOF (n_read < out_size ) and . strtab is
// corrupt (missing terminating NUL; should never happen for valid ELF).
@ -787,7 +795,7 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
// See FindSymbol() comment for description of return value.
FindSymbolResult Symbolizer::GetSymbolFromObjectFile(
const ObjFile & obj, const void *const pc, const ptrdiff_t relocation,
char *out, int out_size, char *tmp_buf, in t tmp_buf_size) {
char *out, size_t out_size, char *tmp_buf, size_ t tmp_buf_size) {
ElfW(Shdr) symtab;
ElfW(Shdr) strtab;
ElfW(Shdr) opd;
@ -810,13 +818,15 @@ FindSymbolResult Symbolizer::GetSymbolFromObjectFile(
// Consult a regular symbol table, then fall back to the dynamic symbol table.
for (const auto symbol_table_type : {SHT_SYMTAB, SHT_DYNSYM}) {
if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum,
obj.elf_header.e_shoff, symbol_table_type,
static_cast< off_t > (obj.elf_header.e_shoff),
static_cast< ElfW ( Word ) > (symbol_table_type),
& symtab, tmp_buf, tmp_buf_size)) {
continue;
}
if (!ReadFromOffsetExact(
obj.fd, & strtab, sizeof(strtab),
obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
static_cast< off_t > (obj.elf_header.e_shoff +
symtab.sh_link * sizeof(symtab)))) {
continue;
}
const FindSymbolResult rc =
@ -858,7 +868,7 @@ class FileDescriptor {
// and snprintf().
class LineReader {
public:
explicit LineReader(int fd, char *buf, in t buf_len)
explicit LineReader(int fd, char *buf, size_ t buf_len)
: fd_(fd),
buf_len_(buf_len),
buf_(buf),
@ -886,12 +896,12 @@ class LineReader {
bol_ = eol_ + 1; // Advance to the next line in the buffer.
SAFE_ASSERT(bol_ < = eod_); // "bol_" can point to "eod_".
if (!HasCompleteLine()) {
const int incomplete_line_length = eod_ - bol_ ;
const auto incomplete_line_length = static_cast< size_t > (eod_ - bol_) ;
// Move the trailing incomplete line to the beginning.
memmove(buf_, bol_, incomplete_line_length);
// Read text from file and append it.
char *const append_pos = buf_ + incomplete_line_length;
const in t capacity_left = buf_len_ - incomplete_line_length;
const size_ t capacity_left = buf_len_ - incomplete_line_length;
const ssize_t num_bytes =
ReadPersistent(fd_, append_pos, capacity_left);
if (num_bytes < = 0) { // EOF or error.
@ -914,7 +924,8 @@ class LineReader {
private:
char *FindLineFeed() const {
return reinterpret_cast< char * > (memchr(bol_, '\n', eod_ - bol_));
return reinterpret_cast< char * > (
memchr(bol_, '\n', static_cast< size_t > (eod_ - bol_)));
}
bool BufferIsEmpty() const { return buf_ == eod_; }
@ -924,7 +935,7 @@ class LineReader {
}
const int fd_;
const in t buf_len_;
const size_ t buf_len_;
char *const buf_;
char *bol_;
char *eol_;
@ -942,7 +953,8 @@ static const char *GetHex(const char *start, const char *end,
int ch = *p;
if ((ch >= '0' & & ch < = '9') || (ch >= 'A' & & ch < = 'F') ||
(ch >= 'a' & & ch < = 'f')) {
hex = (hex < < 4 ) | ( ch < ' A ' ? ch - ' 0 ' : ( ch & 0xF ) + 9 ) ;
hex = (hex < < 4 ) |
static_cast< uint64_t > (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
} else { // Encountered the first non-hex character.
break;
}
@ -974,7 +986,7 @@ static bool ShouldUseMapping(const char *const flags) {
static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap(
bool (*callback)(const char *filename, const void *const start_addr,
const void *const end_addr, uint64_t offset, void *arg),
void *arg, void *tmp_buf, in t tmp_buf_size) {
void *arg, void *tmp_buf, size_ t tmp_buf_size) {
// Use /proc/self/task/< pid > /maps instead of /proc/self/maps. The latter
// requires kernel to stop all threads, and is significantly slower when there
// are 1000s of threads.
@ -1089,10 +1101,10 @@ ObjFile *Symbolizer::FindObjFile(const void *const addr, size_t len) {
}
}
in t lo = 0;
in t hi = addr_map_.Size();
size_ t lo = 0;
size_ t hi = addr_map_.Size();
while (lo < hi ) {
in t mid = (lo + hi) / 2;
size_ t mid = (lo + hi) / 2;
if (addr < addr_map_.At ( mid ) - > end_addr) {
hi = mid;
} else {
@ -1114,7 +1126,7 @@ ObjFile *Symbolizer::FindObjFile(const void *const addr, size_t len) {
}
void Symbolizer::ClearAddrMap() {
for (in t i = 0; i != addr_map_.Size(); i++) {
for (size_ t i = 0; i != addr_map_.Size(); i++) {
ObjFile *o = addr_map_.At(i);
base_internal::LowLevelAlloc::Free(o->filename);
if (o->fd >= 0) {
@ -1134,7 +1146,7 @@ bool Symbolizer::RegisterObjFile(const char *filename,
// Files are supposed to be added in the increasing address order. Make
// sure that's the case.
in t addr_map_size = impl->addr_map_.Size();
size_ t addr_map_size = impl->addr_map_.Size();
if (addr_map_size != 0) {
ObjFile *old = impl->addr_map_.At(addr_map_size - 1);
if (old->end_addr > end_addr) {
@ -1178,12 +1190,12 @@ bool Symbolizer::RegisterObjFile(const char *filename,
// where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, in t out_size,
static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_ t out_size,
char *tmp_buf,
in t tmp_buf_size) {
size_ t tmp_buf_size) {
if (Demangle(out, tmp_buf, tmp_buf_size)) {
// Demangling succeeded. Copy to out if the space allows.
in t len = strlen(tmp_buf);
size_ t len = strlen(tmp_buf);
if (len + 1 < = out_size) { // +1 for '\0'.
SAFE_ASSERT(len < tmp_buf_size ) ;
memmove(out, tmp_buf, len + 1);
@ -1226,7 +1238,8 @@ const char *Symbolizer::InsertSymbolInCache(const void *const pc,
SymbolCacheLine *line = GetCacheLine(pc);
uint32_t max_age = 0;
int oldest_index = -1;
size_t oldest_index = 0;
bool found_oldest_index = false;
for (size_t i = 0; i < ABSL_ARRAYSIZE ( line- > pc); ++i) {
if (line->pc[i] == nullptr) {
AgeSymbols(line);
@ -1238,11 +1251,12 @@ const char *Symbolizer::InsertSymbolInCache(const void *const pc,
if (line->age[i] >= max_age) {
max_age = line->age[i];
oldest_index = i;
found_oldest_index = true;
}
}
AgeSymbols(line);
ABSL_RAW_CHECK(oldest_index >= 0 , "Corrupt cache");
ABSL_RAW_CHECK(found_ oldest_index, "Corrupt cache");
base_internal::LowLevelAlloc::Free(line->name[oldest_index]);
line->pc[oldest_index] = pc;
line->name[oldest_index] = CopyString(name);
@ -1311,7 +1325,7 @@ static bool MaybeInitializeObjFile(ObjFile *obj) {
}
const int phnum = obj->elf_header.e_phnum;
const int phentsize = obj->elf_header.e_phentsize;
size_t phoff = obj->elf_header.e_phoff ;
auto phoff = static_cast< off_t > (obj->elf_header.e_phoff) ;
size_t num_executable_load_segments = 0;
for (int j = 0; j < phnum ; j + + ) {
ElfW(Phdr) phdr;
@ -1362,7 +1376,7 @@ const char *Symbolizer::GetUncachedSymbol(const void *pc) {
//
// For obj->offset > 0, adjust the relocation since a mapping at offset
// X in the file will have a start address of [true relocation]+X.
relocation = start_addr - obj->offset;
relocation = static_cast< ptrdiff_t > (sta rt_addr - obj->offset) ;
// Note: some binaries have multiple "rx" LOAD segments. We must
// find the right one.
@ -1537,7 +1551,7 @@ bool RegisterFileMappingHint(const void *start, const void *end, uint64_t offset
ret = false;
} else {
// TODO(ckennelly): Move this into a string copy routine.
in t len = strlen(filename);
size_ t len = strlen(filename);
char *dst = static_cast< char * > (
base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
ABSL_RAW_CHECK(dst != nullptr, "out of memory");
@ -1593,16 +1607,17 @@ bool Symbolize(const void *pc, char *out, int out_size) {
const char *name = s->GetSymbol(pc);
bool ok = false;
if (name != nullptr & & out_size > 0) {
strncpy(out, name, out_size);
strncpy(out, name, static_cast< size_t > ( out_size) );
ok = true;
if (out[out_size - 1] != '\0') {
if (out[static_cast< size_t > ( out_size) - 1] != '\0') {
// strncpy() does not '\0' terminate when it truncates. Do so, with
// trailing ellipsis.
static constexpr char kEllipsis[] = "...";
int ellipsis_size =
std::min(implicit_cast< int > (strlen(kEllipsis)), out_size - 1);
memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
out[out_size - 1] = '\0';
size_t ellipsis_size =
std::min(strlen(kEllipsis), static_cast< size_t > (out_size) - 1);
memcpy(out + static_cast< size_t > (out_size) - ellipsis_size - 1, kEllipsis,
ellipsis_size);
out[static_cast< size_t > (out_size) - 1] = '\0';
}
}
debugging_internal::FreeSymbolizer(s);