mirror of
https://github.com/dlang/dmd.git
synced 2025-04-27 21:51:03 +03:00
Merge pull request #16104 from denizzzka/avoid_overflow_ex_pr
Partial fix Bugzilla 15504 - core.demangle: remove OverflowException Signed-off-by: Dennis <dkorpel@users.noreply.github.com> Signed-off-by: Razvan Nitu <razvan.nitu1305@gmail.com> Merged-on-behalf-of: Razvan Nitu <razvan.nitu1305@gmail.com>
This commit is contained in:
commit
15ca454e80
1 changed files with 141 additions and 93 deletions
|
@ -118,10 +118,10 @@ pure @safe:
|
||||||
error();
|
error();
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] shift(scope const(char)[] val) return scope
|
BufSlice shift(scope const BufSlice val) return scope
|
||||||
{
|
{
|
||||||
if (mute)
|
if (mute)
|
||||||
return null;
|
return dst.bslice_empty;
|
||||||
return dst.shift(val);
|
return dst.shift(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +138,11 @@ pure @safe:
|
||||||
put(val[]);
|
put(val[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void put(scope BufSlice val) return scope
|
||||||
|
{
|
||||||
|
put(val.getSlice);
|
||||||
|
}
|
||||||
|
|
||||||
void put(scope const(char)[] val) return scope
|
void put(scope const(char)[] val) return scope
|
||||||
{
|
{
|
||||||
if (mute)
|
if (mute)
|
||||||
|
@ -671,7 +676,7 @@ pure @safe:
|
||||||
TypeTuple:
|
TypeTuple:
|
||||||
B Number Arguments
|
B Number Arguments
|
||||||
*/
|
*/
|
||||||
char[] parseType() return scope
|
BufSlice parseType() return scope
|
||||||
{
|
{
|
||||||
static immutable string[23] primitives = [
|
static immutable string[23] primitives = [
|
||||||
"char", // a
|
"char", // a
|
||||||
|
@ -701,14 +706,14 @@ pure @safe:
|
||||||
|
|
||||||
static if (__traits(hasMember, Hooks, "parseType"))
|
static if (__traits(hasMember, Hooks, "parseType"))
|
||||||
if (auto n = hooks.parseType(this, null))
|
if (auto n = hooks.parseType(this, null))
|
||||||
return n;
|
return BufSlice(n, 0, n.length);
|
||||||
|
|
||||||
debug(trace) printf( "parseType+\n" );
|
debug(trace) printf( "parseType+\n" );
|
||||||
debug(trace) scope(success) printf( "parseType-\n" );
|
debug(trace) scope(success) printf( "parseType-\n" );
|
||||||
auto beg = dst.length;
|
auto beg = dst.length;
|
||||||
auto t = front;
|
auto t = front;
|
||||||
|
|
||||||
char[] parseBackrefType(scope char[] delegate() pure @safe parseDg) pure @safe
|
BufSlice parseBackrefType(scope BufSlice delegate() pure @safe parseDg) pure @safe
|
||||||
{
|
{
|
||||||
if (pos == brp)
|
if (pos == brp)
|
||||||
error("recursive back reference");
|
error("recursive back reference");
|
||||||
|
@ -718,7 +723,7 @@ pure @safe:
|
||||||
if (n == 0 || n > pos)
|
if (n == 0 || n > pos)
|
||||||
error("invalid back reference");
|
error("invalid back reference");
|
||||||
if ( mute )
|
if ( mute )
|
||||||
return null;
|
return dst.bslice_empty;
|
||||||
auto savePos = pos;
|
auto savePos = pos;
|
||||||
auto saveBrp = brp;
|
auto saveBrp = brp;
|
||||||
scope(success) { pos = savePos; brp = saveBrp; }
|
scope(success) { pos = savePos; brp = saveBrp; }
|
||||||
|
@ -1215,7 +1220,7 @@ pure @safe:
|
||||||
TypeFunction:
|
TypeFunction:
|
||||||
CallConvention FuncAttrs Arguments ArgClose Type
|
CallConvention FuncAttrs Arguments ArgClose Type
|
||||||
*/
|
*/
|
||||||
char[] parseTypeFunction(IsDelegate isdg = IsDelegate.no) return scope
|
BufSlice parseTypeFunction(IsDelegate isdg = IsDelegate.no) return scope
|
||||||
{
|
{
|
||||||
debug(trace) printf( "parseTypeFunction+\n" );
|
debug(trace) printf( "parseTypeFunction+\n" );
|
||||||
debug(trace) scope(success) printf( "parseTypeFunction-\n" );
|
debug(trace) scope(success) printf( "parseTypeFunction-\n" );
|
||||||
|
@ -1297,7 +1302,13 @@ pure @safe:
|
||||||
E
|
E
|
||||||
F
|
F
|
||||||
*/
|
*/
|
||||||
void parseValue(scope char[] name = null, char type = '\0' ) scope
|
|
||||||
|
void parseValue() scope
|
||||||
|
{
|
||||||
|
parseValue(dst.bslice_empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseValue(scope BufSlice name, char type = '\0' ) scope
|
||||||
{
|
{
|
||||||
debug(trace) printf( "parseValue+\n" );
|
debug(trace) printf( "parseValue+\n" );
|
||||||
debug(trace) scope(success) printf( "parseValue-\n" );
|
debug(trace) scope(success) printf( "parseValue-\n" );
|
||||||
|
@ -1423,8 +1434,12 @@ pure @safe:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parseIntegerValue() scope
|
||||||
|
{
|
||||||
|
parseIntegerValue(dst.bslice_empty);
|
||||||
|
}
|
||||||
|
|
||||||
void parseIntegerValue( scope char[] name = null, char type = '\0' ) scope
|
void parseIntegerValue( scope BufSlice name, char type = '\0' ) scope
|
||||||
{
|
{
|
||||||
debug(trace) printf( "parseIntegerValue+\n" );
|
debug(trace) printf( "parseIntegerValue+\n" );
|
||||||
debug(trace) scope(success) printf( "parseIntegerValue-\n" );
|
debug(trace) scope(success) printf( "parseIntegerValue-\n" );
|
||||||
|
@ -1562,7 +1577,7 @@ pure @safe:
|
||||||
char t = front; // peek at type for parseValue
|
char t = front; // peek at type for parseValue
|
||||||
if ( t == 'Q' )
|
if ( t == 'Q' )
|
||||||
t = peekBackref();
|
t = peekBackref();
|
||||||
char[] name; silent( delegate void() { name = parseType(); } );
|
BufSlice name = dst.bslice_empty; silent( delegate void() { name = parseType(); } );
|
||||||
parseValue( name, t );
|
parseValue( name, t );
|
||||||
continue;
|
continue;
|
||||||
case 'S':
|
case 'S':
|
||||||
|
@ -1755,7 +1770,7 @@ pure @safe:
|
||||||
|
|
||||||
// parse optional function arguments as part of a symbol name, i.e without return type
|
// parse optional function arguments as part of a symbol name, i.e without return type
|
||||||
// if keepAttr, the calling convention and function attributes are not discarded, but returned
|
// if keepAttr, the calling convention and function attributes are not discarded, but returned
|
||||||
char[] parseFunctionTypeNoReturn( bool keepAttr = false ) return scope
|
BufSlice parseFunctionTypeNoReturn( bool keepAttr = false ) return scope
|
||||||
{
|
{
|
||||||
// try to demangle a function, in case we are pointing to some function local
|
// try to demangle a function, in case we are pointing to some function local
|
||||||
auto prevpos = pos;
|
auto prevpos = pos;
|
||||||
|
@ -1777,7 +1792,7 @@ pure @safe:
|
||||||
}
|
}
|
||||||
if ( isCallConvention( front ) )
|
if ( isCallConvention( front ) )
|
||||||
{
|
{
|
||||||
char[] attr;
|
BufSlice attr = dst.bslice_empty;
|
||||||
// we don't want calling convention and attributes in the qualified name
|
// we don't want calling convention and attributes in the qualified name
|
||||||
parseCallConvention();
|
parseCallConvention();
|
||||||
auto attributes = parseFuncAttr();
|
auto attributes = parseFuncAttr();
|
||||||
|
@ -1803,7 +1818,7 @@ pure @safe:
|
||||||
dst.len = prevlen;
|
dst.len = prevlen;
|
||||||
brp = prevbrp;
|
brp = prevbrp;
|
||||||
}
|
}
|
||||||
return null;
|
return dst.bslice_empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1811,7 +1826,7 @@ pure @safe:
|
||||||
SymbolName
|
SymbolName
|
||||||
SymbolName QualifiedName
|
SymbolName QualifiedName
|
||||||
*/
|
*/
|
||||||
char[] parseQualifiedName() return scope
|
BufSlice parseQualifiedName() return scope
|
||||||
{
|
{
|
||||||
debug(trace) printf( "parseQualifiedName+\n" );
|
debug(trace) printf( "parseQualifiedName+\n" );
|
||||||
debug(trace) scope(success) printf( "parseQualifiedName-\n" );
|
debug(trace) scope(success) printf( "parseQualifiedName-\n" );
|
||||||
|
@ -1839,7 +1854,7 @@ pure @safe:
|
||||||
{
|
{
|
||||||
debug(trace) printf( "parseMangledName+\n" );
|
debug(trace) printf( "parseMangledName+\n" );
|
||||||
debug(trace) scope(success) printf( "parseMangledName-\n" );
|
debug(trace) scope(success) printf( "parseMangledName-\n" );
|
||||||
char[] name = null;
|
BufSlice name = dst.bslice_empty;
|
||||||
|
|
||||||
auto end = pos + n;
|
auto end = pos + n;
|
||||||
|
|
||||||
|
@ -1849,10 +1864,10 @@ pure @safe:
|
||||||
{
|
{
|
||||||
size_t beg = dst.length;
|
size_t beg = dst.length;
|
||||||
size_t nameEnd = dst.length;
|
size_t nameEnd = dst.length;
|
||||||
char[] attr;
|
BufSlice attr = dst.bslice_empty;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if ( attr )
|
if ( attr.length )
|
||||||
dst.remove(attr); // dump attributes of parent symbols
|
dst.remove(attr); // dump attributes of parent symbols
|
||||||
if (beg != dst.length)
|
if (beg != dst.length)
|
||||||
put( '.' );
|
put( '.' );
|
||||||
|
@ -1918,18 +1933,7 @@ pure @safe:
|
||||||
{
|
{
|
||||||
debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr );
|
debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr );
|
||||||
FUNC();
|
FUNC();
|
||||||
return dst[0 .. $];
|
return dst[0 .. $].getSlice;
|
||||||
}
|
|
||||||
catch ( OverflowException e )
|
|
||||||
{
|
|
||||||
debug(trace) printf( "overflow... restarting\n" );
|
|
||||||
auto a = Buffer.minSize;
|
|
||||||
auto b = 2 * dst.dst.length;
|
|
||||||
auto newsz = a < b ? b : a;
|
|
||||||
debug(info) printf( "growing dst to %lu bytes\n", newsz );
|
|
||||||
dst.dst.length = newsz;
|
|
||||||
pos = dst.len = brp = 0;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
catch ( ParseException e )
|
catch ( ParseException e )
|
||||||
{
|
{
|
||||||
|
@ -2117,7 +2121,7 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] parseType( ref Remangle d, char[] name = null ) return scope
|
char[] parseType( ref Remangle d, char[] name ) return scope
|
||||||
{
|
{
|
||||||
if (d.front != 'Q')
|
if (d.front != 'Q')
|
||||||
return null;
|
return null;
|
||||||
|
@ -2849,15 +2853,6 @@ private class ParseException : Exception
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto
|
|
||||||
private class OverflowException : Exception
|
|
||||||
{
|
|
||||||
public this(string msg) @safe pure nothrow
|
|
||||||
{
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ditto
|
/// Ditto
|
||||||
private noreturn error(string msg = "Invalid symbol") @trusted pure
|
private noreturn error(string msg = "Invalid symbol") @trusted pure
|
||||||
{
|
{
|
||||||
|
@ -2869,16 +2864,6 @@ private noreturn error(string msg = "Invalid symbol") @trusted pure
|
||||||
: cast(ParseException) __traits(initSymbol, ParseException).ptr;
|
: cast(ParseException) __traits(initSymbol, ParseException).ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto
|
|
||||||
private noreturn overflow(string msg = "Buffer overflow") @trusted pure
|
|
||||||
{
|
|
||||||
version (DigitalMars) pragma(inline, false); // tame dmd inliner
|
|
||||||
|
|
||||||
//throw new OverflowException( msg );
|
|
||||||
debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
|
|
||||||
throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct Buffer
|
private struct Buffer
|
||||||
{
|
{
|
||||||
enum size_t minSize = 4000;
|
enum size_t minSize = 4000;
|
||||||
|
@ -2895,23 +2880,17 @@ private struct Buffer
|
||||||
return this.len;
|
return this.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
public inout(char)[] opSlice (size_t from, size_t to)
|
public BufSlice opSlice (size_t from, size_t to)
|
||||||
inout return scope @safe pure nothrow @nogc
|
return scope @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(from <= to);
|
return bslice(from, to);
|
||||||
assert(to <= len);
|
|
||||||
return this.dst[from .. to];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool contains(scope const(char)[] a, scope const(char)[] b) @trusted
|
static bool contains(scope const(char)[] a, scope const BufSlice b) @safe
|
||||||
{
|
{
|
||||||
if (a.length && b.length)
|
return
|
||||||
{
|
b.from < a.length &&
|
||||||
auto bend = b.ptr + b.length;
|
b.to <= a.length;
|
||||||
auto aend = a.ptr + a.length;
|
|
||||||
return a.ptr <= b.ptr && bend <= aend;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] copyInput(scope const(char)[] buf)
|
char[] copyInput(scope const(char)[] buf)
|
||||||
|
@ -2924,46 +2903,62 @@ private struct Buffer
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkAndStretchBuf(size_t len_to_add) scope
|
||||||
|
{
|
||||||
|
const required = len + len_to_add;
|
||||||
|
|
||||||
|
if (required > dst.length)
|
||||||
|
dst.length = dst.length + len_to_add;
|
||||||
|
}
|
||||||
|
|
||||||
// move val to the end of the dst buffer
|
// move val to the end of the dst buffer
|
||||||
char[] shift(scope const(char)[] val) return scope
|
BufSlice shift(scope const BufSlice val) return scope
|
||||||
{
|
{
|
||||||
version (DigitalMars) pragma(inline, false); // tame dmd inliner
|
version (DigitalMars) pragma(inline, false); // tame dmd inliner
|
||||||
|
|
||||||
if (val.length)
|
if (val.length)
|
||||||
{
|
{
|
||||||
assert( contains( dst[0 .. len], val ) );
|
const ptrdiff_t s = val.from;
|
||||||
debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr );
|
const size_t f = len;
|
||||||
|
|
||||||
if (len + val.length > dst.length)
|
assert(contains( dst[0 .. len], val ),
|
||||||
overflow();
|
"\ndst=\""~dst[0 .. len]~"\"\n"~
|
||||||
size_t v = &val[0] - &dst[0];
|
"val=\""~val.getSlice~"\"\n"
|
||||||
dst[len .. len + val.length] = val[];
|
);
|
||||||
for (size_t p = v; p < len; p++)
|
|
||||||
|
checkAndStretchBuf(val.length);
|
||||||
|
|
||||||
|
// store value temporary over len index
|
||||||
|
dst[len .. len + val.length] = val.getSlice();
|
||||||
|
|
||||||
|
// shift all chars including temporary saved above
|
||||||
|
// if buf was allocated above it will be leave for further usage
|
||||||
|
for (size_t p = s; p < f; p++)
|
||||||
dst[p] = dst[p + val.length];
|
dst[p] = dst[p + val.length];
|
||||||
|
|
||||||
return dst[len - val.length .. len];
|
return bslice(len - val.length, len);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return bslice_empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove val from dst buffer
|
// remove val from dst buffer
|
||||||
void remove(scope const(char)[] val) scope
|
void remove(scope BufSlice val) scope
|
||||||
{
|
{
|
||||||
version (DigitalMars) pragma(inline, false); // tame dmd inliner
|
version (DigitalMars) pragma(inline, false); // tame dmd inliner
|
||||||
|
|
||||||
if ( val.length )
|
if ( val.length )
|
||||||
{
|
{
|
||||||
assert( contains( dst[0 .. len], val ) );
|
assert( contains( dst[0 .. len], val ) );
|
||||||
debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr );
|
|
||||||
size_t v = &val[0] - &dst[0];
|
|
||||||
assert( len >= val.length && len <= dst.length );
|
assert( len >= val.length && len <= dst.length );
|
||||||
len -= val.length;
|
len -= val.length;
|
||||||
for (size_t p = v; p < len; p++)
|
for (size_t p = val.from; p < len; p++)
|
||||||
dst[p] = dst[p + val.length];
|
dst[p] = dst[p + val.length];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] append(scope const(char)[] val) return scope
|
void append(scope const(char)[] val) scope
|
||||||
{
|
{
|
||||||
version (DigitalMars) pragma(inline, false); // tame dmd inliner
|
version (DigitalMars) pragma(inline, false); // tame dmd inliner
|
||||||
|
|
||||||
|
@ -2971,25 +2966,78 @@ private struct Buffer
|
||||||
{
|
{
|
||||||
if ( !dst.length )
|
if ( !dst.length )
|
||||||
dst.length = minSize;
|
dst.length = minSize;
|
||||||
assert( !contains( dst[0 .. len], val ) );
|
|
||||||
debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr );
|
debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr );
|
||||||
|
|
||||||
if ( dst.length - len >= val.length && &dst[len] == &val[0] )
|
checkAndStretchBuf(val.length);
|
||||||
{
|
|
||||||
// data is already in place
|
// data is already not in place?
|
||||||
auto t = dst[len .. len + val.length];
|
if ( &dst[len] != &val[0] )
|
||||||
len += val.length;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
if ( dst.length - len >= val.length )
|
|
||||||
{
|
|
||||||
dst[len .. len + val.length] = val[];
|
dst[len .. len + val.length] = val[];
|
||||||
auto t = dst[len .. len + val.length];
|
|
||||||
len += val.length;
|
len += val.length;
|
||||||
return t;
|
|
||||||
}
|
|
||||||
overflow();
|
|
||||||
}
|
}
|
||||||
return null;
|
}
|
||||||
|
|
||||||
|
@nogc:
|
||||||
|
|
||||||
|
// from index to end of current buf
|
||||||
|
private scope bslice(size_t from) nothrow
|
||||||
|
{
|
||||||
|
return bslice(from, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
private scope bslice(size_t from, size_t to) nothrow
|
||||||
|
{
|
||||||
|
return BufSlice(dst, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
private scope bslice_empty() nothrow
|
||||||
|
{
|
||||||
|
return BufSlice(null, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct BufSlice
|
||||||
|
{
|
||||||
|
char[] dst;
|
||||||
|
|
||||||
|
@safe:
|
||||||
|
pure:
|
||||||
|
nothrow:
|
||||||
|
|
||||||
|
@disable this();
|
||||||
|
|
||||||
|
this(return scope char[] dst) scope nothrow @nogc
|
||||||
|
{
|
||||||
|
this(dst, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this(return scope char[] dst, size_t from, size_t to, bool lastArgIsLen = false) scope nothrow @nogc
|
||||||
|
{
|
||||||
|
this.dst = dst;
|
||||||
|
this.from = from;
|
||||||
|
|
||||||
|
if (lastArgIsLen)
|
||||||
|
this.to = from + to;
|
||||||
|
else
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t from;
|
||||||
|
size_t to;
|
||||||
|
|
||||||
|
invariant()
|
||||||
|
{
|
||||||
|
if (dst is null)
|
||||||
|
{
|
||||||
|
assert(from == 0);
|
||||||
|
assert(to == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(from <= to);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto getSlice() inout nothrow scope { return dst[from .. to]; }
|
||||||
|
size_t length() const scope { return to - from; }
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue