demangle/gcc2: Do not trust inputs.
We do not know anything about the symbols we are being asked to demangle; it is entirely possible they are malformed, or that we parse them incorrectly, which previously led to buffer overflows. E.g. the "2","8" in "SetTo__Q28_GLOBAL_" is presently incorrectly parsed as a length, leading to an access 21 bytes past the end of the string. This caused a page fault under the guarded heap, a fact I had the misfortune to discover when trying to attach Debugger to a guarded-heap'd application which somehow ran the demangler under the guarded heap also, and that symbol above was in runtime_loader, so it crashed while loading its symbols. So now we do what the GCC3+ demangler does here, and keep track of the input buffer through the use of a state class, which will prevent us from incrementing past the buffer's end. I've tested this patch using the new haikuc++filt utility against libtracker (indeed, it took multiple rounds of testing to get the diff to be 0 bytes) and it seems to work exactly as before, though now without out-of-bounds accesses. As this demangler is also used in the kernel, it's possible that some triple-faults on x86_gcc2[h] are caused by this bug (although that would be rare; one of the incorrectly-parsed symbols would have to be in the stack trace, and then it would have to read past the end of the buffer containing the symbol.) Change-Id: I343991cebd7d2887812c8c6b3dc2e0df2fcd79fa Reviewed-on: https://review.haiku-os.org/579 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
adad95fa46
commit
de777b79eb
@@ -19,12 +19,71 @@
|
|||||||
|
|
||||||
//#define TRACE_GCC2_DEMANGLER
|
//#define TRACE_GCC2_DEMANGLER
|
||||||
#ifdef TRACE_GCC2_DEMANGLER
|
#ifdef TRACE_GCC2_DEMANGLER
|
||||||
# define TRACE(x...) kprintf(x)
|
# include <stdio.h>
|
||||||
|
# define TRACE(x...) printf(x)
|
||||||
#else
|
#else
|
||||||
# define TRACE(x...) ;
|
# define TRACE(x...) ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class Input {
|
||||||
|
public:
|
||||||
|
Input(const char* string, size_t length)
|
||||||
|
:
|
||||||
|
fString(string),
|
||||||
|
fLength(length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* String() const
|
||||||
|
{
|
||||||
|
return fString;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CharsRemaining() const
|
||||||
|
{
|
||||||
|
return fLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Skip(size_t count)
|
||||||
|
{
|
||||||
|
if (count > fLength) {
|
||||||
|
TRACE("Input::Skip(): fOffset > fLength\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fString += count;
|
||||||
|
fLength -= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Input& operator++()
|
||||||
|
{
|
||||||
|
Skip(1);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Input operator++(int)
|
||||||
|
{
|
||||||
|
Input result(*this);
|
||||||
|
++(*this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char operator[](size_t index) const
|
||||||
|
{
|
||||||
|
if (index >= fLength) {
|
||||||
|
TRACE("Input::operator[](): fOffset + index >= fLength\n");
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return fString[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* fString;
|
||||||
|
size_t fLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TYPE_FUNCTION,
|
TYPE_FUNCTION,
|
||||||
TYPE_METHOD,
|
TYPE_METHOD,
|
||||||
@@ -32,29 +91,29 @@ enum {
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ignore_qualifiers(const char** _arg)
|
ignore_qualifiers(Input& _arg)
|
||||||
{
|
{
|
||||||
while (isupper(**_arg)) {
|
while (isupper(_arg[0])) {
|
||||||
if (**_arg == 'Q') {
|
if (_arg[0] == 'Q') {
|
||||||
// argument has namespaces
|
// argument has namespaces
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (**_arg == 'F') {
|
if (_arg[0] == 'F') {
|
||||||
// skip function declaration
|
// skip function declaration
|
||||||
while (**_arg && **_arg != '_')
|
while (_arg.CharsRemaining() && _arg[0] != '_')
|
||||||
(*_arg)++;
|
_arg++;
|
||||||
|
|
||||||
if (**_arg == 0)
|
if (!_arg.CharsRemaining())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*_arg)++;
|
_arg++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
argument_type(const char* arg, size_t& length)
|
argument_type(Input arg, size_t& length)
|
||||||
{
|
{
|
||||||
length = sizeof(int);
|
length = sizeof(int);
|
||||||
|
|
||||||
@@ -62,7 +121,7 @@ argument_type(const char* arg, size_t& length)
|
|||||||
case 'P': // pointer
|
case 'P': // pointer
|
||||||
case 'R': // reference
|
case 'R': // reference
|
||||||
length = sizeof(void*);
|
length = sizeof(void*);
|
||||||
ignore_qualifiers(&arg);
|
ignore_qualifiers(arg);
|
||||||
if (arg[0] == 'c')
|
if (arg[0] == 'c')
|
||||||
return B_STRING_TYPE;
|
return B_STRING_TYPE;
|
||||||
if (arg[0] == 't') {
|
if (arg[0] == 't') {
|
||||||
@@ -126,9 +185,9 @@ argument_type(const char* arg, size_t& length)
|
|||||||
|
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
parse_number(const char** _arg, bool numberLeft)
|
parse_number(Input& _arg, bool numberLeft)
|
||||||
{
|
{
|
||||||
const char* arg = *_arg;
|
Input arg = _arg;
|
||||||
|
|
||||||
while (isdigit(arg[0]))
|
while (isdigit(arg[0]))
|
||||||
arg++;
|
arg++;
|
||||||
@@ -137,12 +196,14 @@ parse_number(const char** _arg, bool numberLeft)
|
|||||||
|
|
||||||
if (arg[0] == '_' && (!numberLeft || isdigit(arg[1]))) {
|
if (arg[0] == '_' && (!numberLeft || isdigit(arg[1]))) {
|
||||||
// long value
|
// long value
|
||||||
value = strtoul(*_arg, (char**)_arg, 10);
|
const char* tmp_arg = _arg.String();
|
||||||
if (**_arg == '_')
|
value = strtoul(tmp_arg, (char**)&tmp_arg, 10);
|
||||||
(*_arg)++;
|
_arg.Skip(tmp_arg - _arg.String());
|
||||||
|
if (_arg[0] == '_')
|
||||||
|
_arg++;
|
||||||
} else {
|
} else {
|
||||||
value = **_arg - '0';
|
value = _arg[0] - '0';
|
||||||
(*_arg)++;
|
_arg++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -150,12 +211,12 @@ parse_number(const char** _arg, bool numberLeft)
|
|||||||
|
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
parse_repeats(const char** _arg, uint32& index)
|
parse_repeats(Input& _arg, uint32& index)
|
||||||
{
|
{
|
||||||
if (**_arg != 'N')
|
if (_arg[0] != 'N')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
(*_arg)++;
|
_arg++;
|
||||||
|
|
||||||
uint32 count = parse_number(_arg, true);
|
uint32 count = parse_number(_arg, true);
|
||||||
index = parse_number(_arg, false);
|
index = parse_number(_arg, false);
|
||||||
@@ -165,10 +226,10 @@ parse_repeats(const char** _arg, uint32& index)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
skip_numbers(const char** _arg, int32 count)
|
skip_numbers(Input& _arg, int32 count)
|
||||||
{
|
{
|
||||||
// skip leading character
|
// skip leading character
|
||||||
(*_arg)++;
|
_arg++;
|
||||||
|
|
||||||
while (count-- > 0) {
|
while (count-- > 0) {
|
||||||
parse_number(_arg, count != 0);
|
parse_number(_arg, count != 0);
|
||||||
@@ -177,67 +238,68 @@ skip_numbers(const char** _arg, int32 count)
|
|||||||
|
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
count_namespaces(const char** _mangled)
|
count_namespaces(Input& _mangled)
|
||||||
{
|
{
|
||||||
const char* mangled = *_mangled;
|
Input mangled = _mangled;
|
||||||
|
|
||||||
int32 namespaces = 0;
|
int32 namespaces = 0;
|
||||||
if (mangled[0] == 'Q') {
|
if (mangled[0] == 'Q') {
|
||||||
// more than one namespace
|
// more than one namespace
|
||||||
if (mangled[1] == '_') {
|
if (mangled[1] == '_') {
|
||||||
// more than 9 namespaces
|
// more than 9 namespaces
|
||||||
namespaces = strtoul(mangled + 2, (char**)&mangled, 10);
|
const char* mangled_str = mangled.String();
|
||||||
|
namespaces = strtoul(mangled_str + 2, (char**)&mangled_str, 10);
|
||||||
|
mangled.Skip(mangled_str - mangled.String());
|
||||||
if (mangled[0] != '_')
|
if (mangled[0] != '_')
|
||||||
namespaces = 0;
|
namespaces = 0;
|
||||||
|
|
||||||
mangled++;
|
mangled++;
|
||||||
} else {
|
} else {
|
||||||
namespaces = mangled[1] - '0';
|
namespaces = mangled[1] - '0';
|
||||||
mangled += 2;
|
mangled.Skip(2);
|
||||||
}
|
}
|
||||||
} else if (isdigit(mangled[0]))
|
} else if (isdigit(mangled[0]))
|
||||||
namespaces = 1;
|
namespaces = 1;
|
||||||
|
|
||||||
*_mangled = mangled;
|
_mangled = mangled;
|
||||||
return namespaces;
|
return namespaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
skip_namespaces(const char** _mangled)
|
skip_namespaces(Input& mangled)
|
||||||
{
|
{
|
||||||
const char* mangled = *_mangled;
|
int32 namespaces = count_namespaces(mangled);
|
||||||
int32 namespaces = count_namespaces(&mangled);
|
|
||||||
|
|
||||||
while (namespaces-- > 0) {
|
while (namespaces-- > 0) {
|
||||||
if (!isdigit(mangled[0]))
|
if (!isdigit(mangled[0]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
mangled += strtoul(mangled, (char**)&mangled, 10);
|
const char* mangled_str = mangled.String();
|
||||||
|
mangled_str += strtoul(mangled_str, (char**)&mangled_str, 10);
|
||||||
|
mangled.Skip(mangled_str - mangled.String());
|
||||||
}
|
}
|
||||||
|
|
||||||
*_mangled = mangled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
has_named_argument(const char** _arg)
|
has_named_argument(Input& arg)
|
||||||
{
|
{
|
||||||
ignore_qualifiers(_arg);
|
ignore_qualifiers(arg);
|
||||||
|
|
||||||
// See if it's a built-in type
|
// See if it's a built-in type
|
||||||
return **_arg == 'Q' || isdigit(**_arg);
|
return arg[0] == 'Q' || isdigit(arg[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32
|
static uint32
|
||||||
argument_length(const char** _arg)
|
argument_length(Input& _arg)
|
||||||
{
|
{
|
||||||
if (**_arg == 'N') {
|
if (_arg[0] == 'N') {
|
||||||
// skip repeats
|
// skip repeats
|
||||||
skip_numbers(_arg, 2);
|
skip_numbers(_arg, 2);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (**_arg == 'T') {
|
} else if (_arg[0] == 'T') {
|
||||||
// skip reference
|
// skip reference
|
||||||
skip_numbers(_arg, 1);
|
skip_numbers(_arg, 1);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -245,59 +307,54 @@ argument_length(const char** _arg)
|
|||||||
|
|
||||||
ignore_qualifiers(_arg);
|
ignore_qualifiers(_arg);
|
||||||
|
|
||||||
if (!**_arg)
|
if (!_arg.CharsRemaining())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// See if it's a built-in type
|
// See if it's a built-in type
|
||||||
if (**_arg != 'Q' && !isdigit(**_arg))
|
if (_arg[0] != 'Q' && !isdigit(_arg[0]))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
const char* mangled = *_arg;
|
Input mangled = _arg;
|
||||||
skip_namespaces(&mangled);
|
skip_namespaces(mangled);
|
||||||
|
|
||||||
return mangled - *_arg;
|
return mangled.String() - _arg.String();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char*
|
static Input
|
||||||
next_argument(const char* arg)
|
next_argument(Input arg)
|
||||||
{
|
{
|
||||||
if (arg == NULL || !arg[0])
|
if (!arg.CharsRemaining() || !arg[0])
|
||||||
return NULL;
|
return arg;
|
||||||
|
|
||||||
uint32 length = argument_length(&arg);
|
uint32 length = argument_length(arg);
|
||||||
arg += length;
|
arg.Skip(length);
|
||||||
|
|
||||||
if (!arg[0])
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char*
|
static Input
|
||||||
first_argument(const char* mangled)
|
first_argument(Input mangled)
|
||||||
{
|
{
|
||||||
skip_namespaces(&mangled);
|
skip_namespaces(mangled);
|
||||||
|
|
||||||
return mangled;
|
return mangled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char*
|
static bool
|
||||||
mangled_start(const char* name, size_t* _symbolLength, int32* _symbolType)
|
mangled_start(Input& name, size_t* _symbolLength, int32* _symbolType)
|
||||||
{
|
{
|
||||||
if (name == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// search '__' starting from the end, don't accept them at the start
|
// search '__' starting from the end, don't accept them at the start
|
||||||
size_t pos = strlen(name) - 1;
|
size_t pos = name.CharsRemaining() - 1;
|
||||||
const char* mangled = NULL;
|
bool foundStart = false;
|
||||||
|
|
||||||
while (pos > 1) {
|
while (pos > 1) {
|
||||||
if (name[pos] == '_') {
|
if (name[pos] == '_') {
|
||||||
if (name[pos - 1] == '_') {
|
if (name[pos - 1] == '_') {
|
||||||
mangled = name + pos + 1;
|
foundStart = true;
|
||||||
|
name.Skip(pos + 1);
|
||||||
break;
|
break;
|
||||||
} else
|
} else
|
||||||
pos--;
|
pos--;
|
||||||
@@ -305,26 +362,27 @@ mangled_start(const char* name, size_t* _symbolLength, int32* _symbolType)
|
|||||||
pos--;
|
pos--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mangled == NULL)
|
if (!foundStart)
|
||||||
return NULL;
|
return false;
|
||||||
|
|
||||||
if (mangled[0] == 'H') {
|
if (name[0] == 'H') {
|
||||||
// TODO: we don't support templates yet
|
// TODO: we don't support templates yet
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_symbolLength != NULL)
|
if (_symbolLength != NULL)
|
||||||
*_symbolLength = pos - 1;
|
*_symbolLength = pos - 1;
|
||||||
|
|
||||||
if (mangled[0] == 'F') {
|
if (name[0] == 'F') {
|
||||||
if (_symbolType != NULL)
|
if (_symbolType != NULL)
|
||||||
*_symbolType = TYPE_FUNCTION;
|
*_symbolType = TYPE_FUNCTION;
|
||||||
return mangled + 1;
|
name.Skip(1);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_symbolType != NULL)
|
if (_symbolType != NULL)
|
||||||
*_symbolType = TYPE_METHOD;
|
*_symbolType = TYPE_METHOD;
|
||||||
return mangled;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -332,11 +390,11 @@ static status_t
|
|||||||
get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
|
get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
|
||||||
size_t nameSize, int32* _type, size_t* _argumentLength, bool repeating)
|
size_t nameSize, int32* _type, size_t* _argumentLength, bool repeating)
|
||||||
{
|
{
|
||||||
const char* mangled = mangled_start(symbol, NULL, NULL);
|
Input mangled(symbol, strlen(symbol));
|
||||||
if (mangled == NULL)
|
if (!mangled_start(mangled, NULL, NULL))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
const char* arg = first_argument(mangled);
|
Input arg = first_argument(mangled);
|
||||||
|
|
||||||
// (void) is not an argument
|
// (void) is not an argument
|
||||||
if (arg[0] == 'v')
|
if (arg[0] == 'v')
|
||||||
@@ -348,10 +406,10 @@ get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
|
|||||||
|
|
||||||
for (uint32 i = 0; i < current; i++) {
|
for (uint32 i = 0; i < current; i++) {
|
||||||
arg = next_argument(arg);
|
arg = next_argument(arg);
|
||||||
if (arg != NULL && arg[0] == 'N') {
|
if (arg.CharsRemaining() && arg[0] == 'N') {
|
||||||
// repeat argument 'count' times
|
// repeat argument 'count' times
|
||||||
uint32 index;
|
uint32 index;
|
||||||
uint32 count = parse_repeats(&arg, index);
|
uint32 count = parse_repeats(arg, index);
|
||||||
if (current <= i + count) {
|
if (current <= i + count) {
|
||||||
if (repeating)
|
if (repeating)
|
||||||
return B_LINK_LIMIT;
|
return B_LINK_LIMIT;
|
||||||
@@ -368,10 +426,10 @@ get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg == NULL)
|
if (arg[0] == '\0' || !arg.CharsRemaining())
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
TRACE("\n\targ %ld: %s\n", current, arg);
|
TRACE("\n\targ %ld: %s\n", current, arg.String());
|
||||||
|
|
||||||
if (arg[0] == 'T') {
|
if (arg[0] == 'T') {
|
||||||
// duplicate argument
|
// duplicate argument
|
||||||
@@ -379,7 +437,7 @@ get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
|
|||||||
return B_LINK_LIMIT;
|
return B_LINK_LIMIT;
|
||||||
|
|
||||||
arg++;
|
arg++;
|
||||||
uint32 index = parse_number(&arg, false);
|
uint32 index = parse_number(arg, false);
|
||||||
status_t status = get_next_argument_internal(&index, symbol, name,
|
status_t status = get_next_argument_internal(&index, symbol, name,
|
||||||
nameSize, _type, _argumentLength, true);
|
nameSize, _type, _argumentLength, true);
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
@@ -400,11 +458,11 @@ get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
|
|||||||
*_argumentLength = argumentLength;
|
*_argumentLength = argumentLength;
|
||||||
|
|
||||||
name[0] = '\0';
|
name[0] = '\0';
|
||||||
if (!has_named_argument(&arg))
|
if (!has_named_argument(arg))
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
const char* namespaceStart = arg;
|
Input namespaceStart = arg;
|
||||||
int32 namespaces = count_namespaces(&namespaceStart);
|
int32 namespaces = count_namespaces(namespaceStart);
|
||||||
|
|
||||||
while (namespaces-- > 0) {
|
while (namespaces-- > 0) {
|
||||||
if (namespaceStart[0] == 't') {
|
if (namespaceStart[0] == 't') {
|
||||||
@@ -414,12 +472,15 @@ get_next_argument_internal(uint32* _cookie, const char* symbol, char* name,
|
|||||||
if (!isdigit(namespaceStart[0]))
|
if (!isdigit(namespaceStart[0]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
uint32 length = strtoul(namespaceStart, (char**)&namespaceStart, 10);
|
const char* ns_str = namespaceStart.String();
|
||||||
|
uint32 length = strtoul(ns_str, (char**)&ns_str, 10);
|
||||||
|
namespaceStart.Skip(ns_str - namespaceStart.String());
|
||||||
|
|
||||||
uint32 max = strlen(name) + length + 1;
|
uint32 max = strlen(name) + length + 1;
|
||||||
strlcat(name, namespaceStart, min_c(max, nameSize));
|
strlcat(name, namespaceStart.String(), min_c(max, nameSize));
|
||||||
if (namespaces > 0)
|
if (namespaces > 0)
|
||||||
strlcat(name, "::", nameSize);
|
strlcat(name, "::", nameSize);
|
||||||
namespaceStart += length;
|
namespaceStart.Skip(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -433,10 +494,13 @@ const char*
|
|||||||
demangle_symbol_gcc2(const char* name, char* buffer, size_t bufferSize,
|
demangle_symbol_gcc2(const char* name, char* buffer, size_t bufferSize,
|
||||||
bool* _isObjectMethod)
|
bool* _isObjectMethod)
|
||||||
{
|
{
|
||||||
|
if (name == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
size_t nameLength;
|
size_t nameLength;
|
||||||
int32 type;
|
int32 type;
|
||||||
const char* mangled = mangled_start(name, &nameLength, &type);
|
Input mangled(name, strlen(name));
|
||||||
if (mangled == NULL)
|
if (!mangled_start(mangled, &nameLength, &type))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (mangled[0] == 'C') {
|
if (mangled[0] == 'C') {
|
||||||
@@ -450,8 +514,8 @@ demangle_symbol_gcc2(const char* name, char* buffer, size_t bufferSize,
|
|||||||
*_isObjectMethod = type == TYPE_METHOD;
|
*_isObjectMethod = type == TYPE_METHOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* namespaceStart = mangled;
|
Input namespaceStart = mangled;
|
||||||
int32 namespaces = count_namespaces(&namespaceStart);
|
int32 namespaces = count_namespaces(namespaceStart);
|
||||||
|
|
||||||
buffer[0] = '\0';
|
buffer[0] = '\0';
|
||||||
|
|
||||||
@@ -463,11 +527,14 @@ demangle_symbol_gcc2(const char* name, char* buffer, size_t bufferSize,
|
|||||||
if (!isdigit(namespaceStart[0]))
|
if (!isdigit(namespaceStart[0]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
uint32 length = strtoul(namespaceStart, (char**)&namespaceStart, 10);
|
const char* ns_str = namespaceStart.String();
|
||||||
|
uint32 length = strtoul(ns_str, (char**)&ns_str, 10);
|
||||||
|
namespaceStart.Skip(ns_str - namespaceStart.String());
|
||||||
|
|
||||||
uint32 max = strlen(buffer) + length + 1;
|
uint32 max = strlen(buffer) + length + 1;
|
||||||
strlcat(buffer, namespaceStart, min_c(max, bufferSize));
|
strlcat(buffer, namespaceStart.String(), min_c(max, bufferSize));
|
||||||
strlcat(buffer, "::", bufferSize);
|
strlcat(buffer, "::", bufferSize);
|
||||||
namespaceStart += length;
|
namespaceStart.Skip(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t max = strlen(buffer) + nameLength + 1;
|
size_t max = strlen(buffer) + nameLength + 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user