From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 110388 invoked by alias); 30 Nov 2018 17:41:50 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 110369 invoked by uid 89); 30 Nov 2018 17:41:49 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.1 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,SPF_HELO_PASS,T_FILL_THIS_FORM_SHORT,UNSUBSCRIBE_BODY autolearn=ham version=3.3.2 spammy=enhanced, java, mutually, gross X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 30 Nov 2018 17:41:40 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 37A6130C582C; Fri, 30 Nov 2018 17:41:39 +0000 (UTC) Received: from [10.36.116.66] (ovpn-116-66.ams2.redhat.com [10.36.116.66]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E8EA967644; Fri, 30 Nov 2018 17:41:36 +0000 (UTC) To: Jakub Jelinek , matz@gcc.gnu.org, sgayou@redhat.com, Ian Lance Taylor , Pedro Alves , Tom Tromey References: <87muprdko7.fsf@redhat.com> <20181130084211.GX12380@tucnak> <173817ca-0aa0-e1a2-6725-37e079ead545@redhat.com> <20181130140330.GA12380@tucnak> Cc: gcc-patches@gcc.gnu.org, binutils@sourceware.org, jason@redhat.com From: Nick Clifton Openpgp: preference=signencrypt Subject: Re: RFA/RFC: Add stack recursion limit to libiberty's demangler [v3] Message-ID: Date: Fri, 30 Nov 2018 17:41:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.0 MIME-Version: 1.0 In-Reply-To: <20181130140330.GA12380@tucnak> Content-Type: multipart/mixed; boundary="------------40E57977C7277D321F77D8E0" X-IsSubscribed: yes X-SW-Source: 2018-11/txt/msg02589.txt.bz2 This is a multi-part message in MIME format. --------------40E57977C7277D321F77D8E0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Content-length: 3776 Hi Guys, >> I think it would be fine to have a large fixed limit plus a flag to >> disable the limit. Great - in which case please may I present version 3 of the patch. In this version: * The cplus_demangle_set_recursion_limit() function has been removed and instead a new constant - DEMANGLE_RECURSION_LIMIT - is defined in demangle.h. * The recursion counters in cp-demangle.c have been merged into one counter, now contained in the d_info structure. * In cplus-dem.c the recursion counter has been moved into the work structure. * The description of the DMGL_RECURSE_LIMIT option in demangle.h has been enhanced to add a note that if the option is not used, then bug reports about stack overflows in the demangler will be rejected. * The binutils patch has been updated to reflect these changes. The addr2line, cxxfilt, nm and objdump programs now have two new options --recurse-limit and --no-recurse-limit, with --recurse-limit being the default. The documentation is updated to describe these options and to also add a note about bug reports being rejected if --no-recurse-limit is used. What do you think, is this version acceptable ? Cheers Nick libiberty/ChangeLog 2018-11-29 Nick Clifton PR 87681 PR 87675 PR 87636 PR 87335 * cp-demangle.h (struct d_info): Add recursion_limit field. * cp-demangle.c (d_function_type): If the recursion limit is enabled and reached, return with a failure result. (d_demangle_callback): If the recursion limit is enabled, check for a mangled string that is so long that there is not enough stack space for the local arrays. * cplus-dem.c (struct work): Add recursion_level field. (demangle_nested_args): If the recursion limit is enabled and reached, return with a failure result. include/ChangeLog 2018-11-29 Nick Clifton * demangle.h (DMGL_RECURSE_LIMIT): Define. (DEMANGLE_RECURSION_LIMIT): Prototype. binutils/ChangeLog 2018-11-29 Nick Clifton * addr2line.c (demangle_flags): New static variable. (long_options): Add --recurse-limit and --no-recurse-limit. (translate_address): Pass demangle_flags to bfd_demangle. (main): Handle --recurse-limit and --no-recurse-limit options. * cxxfilt.c (flags): Add DMGL_RECURSE_LIMIT. (long_options): Add --recurse-limit and --no-recurse-limit. (main): Handle new options. * dlltool.c (gen_def_file): Include DMGL_RECURSE_LIMIT in flags passed to cplus_demangle. * nm.c (demangle_flags): New static variable. (long_options): Add --recurse-limit and --no-recurse-limit. (main): Handle new options. * objdump.c (demangle_flags): New static variable. (usage): Add --recurse-limit and --no-recurse-limit. (long_options): Likewise. (objdump_print_symname): Pass demangle_flags to bfd_demangle. (disassemble_section): Likewise. (dump_dymbols): Likewise. (main): Handle new options. * prdbg.c (demangle_flags): New static variable. (tg_variable): Pass demangle_flags to demangler. (tg_start_function): Likewise. * stabs.c (demangle_flags): New static variable. (stab_demangle_template): Pass demangle_flags to demangler. (stab_demangle_v3_argtypes): Likewise. (stab_demangle_v3_arg): Likewise. * doc/binutuls.texi: Document new command line options. * NEWS: Mention the new feature. * testsuite/config/default.exp (CXXFILT): Define if not already defined. (CXXFILTFLAGS): Likewise. * testsuite/binutils-all/cxxfilt.exp: New file. Runs a few simple tests of the cxxfilt program. --------------40E57977C7277D321F77D8E0 Content-Type: text/x-patch; name="binutils-demangler-recursion-limit.3.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="binutils-demangler-recursion-limit.3.patch" Content-length: 25903 diff --git a/binutils/NEWS b/binutils/NEWS index a3ee86ef7f..5ed61c8513 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,5 +1,16 @@ -*- text -*- =20 +* The addr2line, c++filt, nm and objdump tools now have a limit on the + maximum amount of recursion that is allowed whilst demangling strings. + The value for this limit is defined by the DEMANGLE_RECRUSE_LIMIT + constant declared in the include/demangle.h header file. At the time + of writing this constant has the value of 1024. + + The --no-recurse-limit option can be used to remove the limit, restoring + the behaviour of earlier versions of these tools. This may be needed in + order to dmangle truely complicated names, but it also leaves the tools + vulnerable to stack exhaustion from maliciously constructed mangled name= s. + * Objdump's --disassemble option can now take a parameter, specifying the starting symbol for disassembly. Disassembly will continue from this symbol up to the next symbol. diff --git a/binutils/addr2line.c b/binutils/addr2line.c index 008e62026e..3085806a4a 100644 --- a/binutils/addr2line.c +++ b/binutils/addr2line.c @@ -45,6 +45,9 @@ static bfd_boolean do_demangle; /* -C, demangle names. = */ static bfd_boolean pretty_print; /* -p, print on one line. */ static bfd_boolean base_names; /* -s, strip directory names. */ =20 +/* Flags passed to the name demangler. */ +static int demangle_flags =3D DMGL_PARAMS | DMGL_ANSI | DMGL_RECURSE_LIMIT; + static int naddr; /* Number of addresses to process. */ static char **addr; /* Hex addresses to process. */ =20 @@ -59,6 +62,10 @@ static struct option long_options[] =3D {"functions", no_argument, NULL, 'f'}, {"inlines", no_argument, NULL, 'i'}, {"pretty-print", no_argument, NULL, 'p'}, + {"recurse-limit", no_argument, NULL, 'R'}, + {"recursion-limit", no_argument, NULL, 'R'},=20=20 + {"no-recurse-limit", no_argument, NULL, 'r'}, + {"no-recursion-limit", no_argument, NULL, 'r'},=20=20 {"section", required_argument, NULL, 'j'}, {"target", required_argument, NULL, 'b'}, {"help", no_argument, NULL, 'H'}, @@ -91,6 +98,8 @@ usage (FILE *stream, int status) -s --basenames Strip directory names\n\ -f --functions Show function names\n\ -C --demangle[=3Dstyle] Demangle function names\n\ + -R --recurse-limit Enable a limit on recursion whilst demangling. [= Default]\n\ + -r --no-recurse-limit Disable a limit on recursion whilst demangling\n\ -h --help Display this information\n\ -v --version Display the program's version\n\ \n")); @@ -289,7 +298,7 @@ translate_addresses (bfd *abfd, asection *section) name =3D "??"; else if (do_demangle) { - alloc =3D bfd_demangle (abfd, name, DMGL_ANSI | DMGL= _PARAMS); + alloc =3D bfd_demangle (abfd, name, demangle_flags); if (alloc !=3D NULL) name =3D alloc; } @@ -442,7 +451,7 @@ main (int argc, char **argv) file_name =3D NULL; section_name =3D NULL; target =3D NULL; - while ((c =3D getopt_long (argc, argv, "ab:Ce:sfHhij:pVv", long_options,= (int *) 0)) + while ((c =3D getopt_long (argc, argv, "ab:Ce:rRsfHhij:pVv", long_option= s, (int *) 0)) !=3D EOF) { switch (c) @@ -469,6 +478,12 @@ main (int argc, char **argv) cplus_demangle_set_style (style); } break; + case 'R': + demangle_flags |=3D DMGL_RECURSE_LIMIT; + break; + case 'r': + demangle_flags &=3D ~ DMGL_RECURSE_LIMIT; + break; case 'e': file_name =3D optarg; break; diff --git a/binutils/cxxfilt.c b/binutils/cxxfilt.c index e7272445c9..f1027c020c 100644 --- a/binutils/cxxfilt.c +++ b/binutils/cxxfilt.c @@ -29,7 +29,7 @@ #include "safe-ctype.h" #include "bucomm.h" =20 -static int flags =3D DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE; +static int flags =3D DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE | DMGL_RECURSE= _LIMIT; static int strip_underscore =3D TARGET_PREPENDS_UNDERSCORE; =20 static const struct option long_options[] =3D @@ -42,6 +42,10 @@ static const struct option long_options[] =3D {"no-verbose", no_argument, NULL, 'i'}, {"types", no_argument, NULL, 't'}, {"version", no_argument, NULL, 'v'}, + {"recurse-limit", no_argument, NULL, 'R'}, + {"recursion-limit", no_argument, NULL, 'R'}, + {"no-recurse-limit", no_argument, NULL, 'r'}, + {"no-recursion-limit", no_argument, NULL, 'r'}, {NULL, no_argument, NULL, 0} }; =20 @@ -102,6 +106,8 @@ Options are:\n\ fprintf (stream, "\ [-p|--no-params] Do not display function arguments\n\ [-i|--no-verbose] Do not show implementation details (if any)\= n\ + [-R|--recurse-limit] Enable a limit on recursion whilst demanglin= g. [Default]\n\ + ]-r|--no-recurse-limit] Disable a limit on recursion whilst demangli= ng\n\ [-t|--types] Also attempt to demangle type encodings\n\ [-s|--format "); print_demangler_list (stream); @@ -180,7 +186,7 @@ main (int argc, char **argv) =20 expandargv (&argc, &argv); =20 - while ((c =3D getopt_long (argc, argv, "_hinps:tv", long_options, (int *= ) 0)) !=3D EOF) + while ((c =3D getopt_long (argc, argv, "_hinprRs:tv", long_options, (int= *) 0)) !=3D EOF) { switch (c) { @@ -195,6 +201,12 @@ main (int argc, char **argv) case 'p': flags &=3D ~ DMGL_PARAMS; break; + case 'R': + flags |=3D DMGL_RECURSE_LIMIT; + break; + case 'r': + flags &=3D ~ DMGL_RECURSE_LIMIT; + break; case 't': flags |=3D DMGL_TYPES; break; diff --git a/binutils/dlltool.c b/binutils/dlltool.c index 2c751241f1..963d541b8e 100644 --- a/binutils/dlltool.c +++ b/binutils/dlltool.c @@ -1802,7 +1802,7 @@ gen_def_file (void) for (i =3D 0, exp =3D d_exports; exp; i++, exp =3D exp->next) { char *quote =3D strchr (exp->name, '.') ? "\"" : ""; - char *res =3D cplus_demangle (exp->internal_name, DMGL_ANSI | DMGL_P= ARAMS); + char *res =3D cplus_demangle (exp->internal_name, DMGL_ANSI | DMGL_P= ARAMS | DMGL_RECURSE_LIMIT); =20 if (res) { diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 9954adf484..0f1b493e39 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -769,7 +769,9 @@ nm [@option{-A}|@option{-o}|@option{--print-file-name}]= [@option{-a}|@option{--d [@option{-s}|@option{--print-armap}] [@option{-t} @var{radix}|@option{-= -radix=3D}@var{radix}] [@option{-u}|@option{--undefined-only}] [@option{-V}|@option{--version}] [@option{-X 32_64}] [@option{--defined-only}] [@option{--no-demangle}] - [@option{--plugin} @var{name}] [@option{--size-sort}] [@option{--specia= l-syms}] + [@option{--plugin} @var{name}] + [@option{--no-recurse-limit}|@option{--recurse-limit}]] + [@option{--size-sort}] [@option{--special-syms}] [@option{--synthetic}] [@option{--with-symbol-versions}] [@option{--tar= get=3D}@var{bfdname}] [@var{objfile}@dots{}] @c man end @@ -939,6 +941,22 @@ for more information on demangling. @item --no-demangle Do not demangle low-level symbol names. This is the default. =20 +@item --recurse-limit +@itemx --no-recurse-limit +@itemx --recursion-limit +@itemx --no-recursion-limit +Enables or disables a limit on the amount of recursion performed +whilst demangling strings. Since the name mangling formats allow for +an inifinite level of recursion it is possible to create strings whose +decoding will exhaust the amount of stack space available on the host +machine, triggering a memory fault. The limit tries to prevent this +from happening by restricting recursion to 1024 levels of nesting. + +The default is for this limit to be enabled, but disabling it may be +necessary in order to demangle truely complicated names. Note however +that if the recursion limit is disabled then stack exhaustion is +possible and any bug reports about such an event will be rejected. + @item -D @itemx --dynamic @cindex dynamic symbols @@ -2098,6 +2116,7 @@ objdump [@option{-a}|@option{--archive-headers}] [@option{--adjust-vma=3D}@var{offset}] [@option{--dwarf-depth=3D@var{n}}] [@option{--dwarf-start=3D@var{n}}] + [@option{--no-recurse-limit}|@option{--recurse-limit}] [@option{--special-syms}] [@option{--prefix=3D}@var{prefix}] [@option{--prefix-strip=3D}@var{level}] @@ -2174,6 +2193,22 @@ mangling styles. The optional demangling style argum= ent can be used to choose an appropriate demangling style for your compiler. @xref{c++filt}, for more information on demangling. =20 +@item --recurse-limit +@itemx --no-recurse-limit +@itemx --recursion-limit +@itemx --no-recursion-limit +Enables or disables a limit on the amount of recursion performed +whilst demangling strings. Since the name mangling formats allow for +an inifinite level of recursion it is possible to create strings whose +decoding will exhaust the amount of stack space available on the host +machine, triggering a memory fault. The limit tries to prevent this +from happening by restricting recursion to 1024 levels of nesting. + +The default is for this limit to be enabled, but disabling it may be +necessary in order to demangle truely complicated names. Note however +that if the recursion limit is disabled then stack exhaustion is +possible and any bug reports about such an event will be rejected. + @item -g @itemx --debugging Display debugging information. This attempts to parse STABS @@ -3403,6 +3438,8 @@ c++filt [@option{-_}|@option{--strip-underscore}] [@option{-p}|@option{--no-params}] [@option{-t}|@option{--types}] [@option{-i}|@option{--no-verbose}] + [@option{-r}|@option{--no-recurse-limit}] + [@option{-R}|@option{--recurse-limit}] [@option{-s} @var{format}|@option{--format=3D}@var{format}] [@option{--help}] [@option{--version}] [@var{symbol}@dots{}] @c man end @@ -3507,6 +3544,28 @@ demangled to ``signed char''. Do not include implementation details (if any) in the demangled output. =20 +@item -r +@itemx -R +@itemx --recurse-limit +@itemx --no-recurse-limit +@itemx --recursion-limit +@itemx --no-recursion-limit +Enables or disables a limit on the amount of recursion performed +whilst demangling strings. Since the name mangling formats allow for +an inifinite level of recursion it is possible to create strings whose +decoding will exhaust the amount of stack space available on the host +machine, triggering a memory fault. The limit tries to prevent this +from happening by restricting recursion to 1024 levels of nesting. + +The default is for this limit to be enabled, but disabling it may be +necessary in order to demangle truely complicated names. Note however +that if the recursion limit is disabled then stack exhaustion is +possible and any bug reports about such an event will be rejected. + +The @option{-r} option is a snyonym for the +@option{--no-recurse-limit} option. The @option{-R} option is a +synonym for the @option{--recurse-limit} option. + @item -s @var{format} @itemx --format=3D@var{format} @command{c++filt} can decode various methods of mangling, used by @@ -3580,6 +3639,8 @@ c++filt @var{option} @var{symbol} addr2line [@option{-a}|@option{--addresses}] [@option{-b} @var{bfdname}|@option{--target=3D}@var{bfdname}] [@option{-C}|@option{--demangle}[=3D@var{style}]] + [@option{-r}|@option{--no-recurse-limit}] + [@option{-R}|@option{--recurse-limit}] [@option{-e} @var{filename}|@option{--exe=3D}@var{filename}] [@option{-f}|@option{--functions}] [@option{-s}|@option{--basena= me}] [@option{-i}|@option{--inlines}] @@ -3705,6 +3766,32 @@ Read offsets relative to the specified section inste= ad of absolute addresses. Make the output more human friendly: each location are printed on one line. If option @option{-i} is specified, lines for all enclosing scopes are prefixed with @samp{(inlined by)}. + +@item -r +@itemx -R +@itemx --recurse-limit +@itemx --no-recurse-limit +@itemx --recursion-limit +@itemx --no-recursion-limit +Enables or disables a limit on the amount of recursion performed +whilst demangling strings. Since the name mangling formats allow for +an inifinite level of recursion it is possible to create strings whose +decoding will exhaust the amount of stack space available on the host +machine, triggering a memory fault. The limit tries to prevent this +from happening by restricting recursion to 1024 levels of nesting. + +The default is for this limit to be enabled, but disabling it may be +necessary in order to demangle truely complicated names. Note however +that if the recursion limit is disabled then stack exhaustion is +possible and any bug reports about such an event will be rejected. + +The @option{-r} option is a snyonym for the +@option{--no-recurse-limit} option. The @option{-R} option is a +synonym for the @option{--recurse-limit} option. + +Note this option is only effective if the @option{-C} or +@option{--demangle} option has been enabled. + @end table =20 @c man end diff --git a/binutils/nm.c b/binutils/nm.c index bc4fccb5fc..1172d6222c 100644 --- a/binutils/nm.c +++ b/binutils/nm.c @@ -162,6 +162,8 @@ static int line_numbers =3D 0; /* Print line numbers fo= r symbols. */ static int allow_special_symbols =3D 0; /* Allow special symbols. */ static int with_symbol_versions =3D 0; /* Include symbol version informati= on in the output. */ =20 +static int demangle_flags =3D DMGL_ANSI | DMGL_PARAMS | DMGL_RECURSE_LIMIT; + /* When to print the names of files. Not mutually exclusive in SYSV forma= t. */ static int filename_per_file =3D 0; /* Once per file, on its own line. */ static int filename_per_symbol =3D 0; /* Once per symbol, at start of line= . */ @@ -194,9 +196,14 @@ static const char *plugin_target =3D NULL; static bfd *lineno_cache_bfd; static bfd *lineno_cache_rel_bfd; =20 -#define OPTION_TARGET 200 -#define OPTION_PLUGIN (OPTION_TARGET + 1) -#define OPTION_SIZE_SORT (OPTION_PLUGIN + 1) +enum long_option_values +{ + OPTION_TARGET =3D 200, + OPTION_PLUGIN, + OPTION_SIZE_SORT, + OPTION_RECURSE_LIMIT, + OPTION_NO_RECURSE_LIMIT +}; =20 static struct option long_options[] =3D { @@ -209,6 +216,8 @@ static struct option long_options[] =3D {"line-numbers", no_argument, 0, 'l'}, {"no-cplus", no_argument, &do_demangle, 0}, /* Linux compatibility. */ {"no-demangle", no_argument, &do_demangle, 0}, + {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, + {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, {"no-sort", no_argument, 0, 'p'}, {"numeric-sort", no_argument, 0, 'n'}, {"plugin", required_argument, 0, OPTION_PLUGIN}, @@ -217,6 +226,8 @@ static struct option long_options[] =3D {"print-file-name", no_argument, 0, 'o'}, {"print-size", no_argument, 0, 'S'}, {"radix", required_argument, 0, 't'}, + {"recurse-limit", no_argument, NULL, OPTION_RECURSE_LIMIT}, + {"recursion-limit", no_argument, NULL, OPTION_RECURSE_LIMIT}, {"reverse-sort", no_argument, &reverse_sort, 1}, {"size-sort", no_argument, 0, OPTION_SIZE_SORT}, {"special-syms", no_argument, &allow_special_symbols, 1}, @@ -245,6 +256,8 @@ usage (FILE *stream, int status) `gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `j= ava'\n\ or `gnat'\n\ --no-demangle Do not demangle low-level symbol names\n\ + --recurse-limit Enable a demangling recursion limit. This is the= default.\n\ + --no-recurse-limit Disable a demangling recursion limit.\n\ -D, --dynamic Display dynamic symbols instead of normal symbols= \n\ --defined-only Display only defined symbols\n\ -e (ignored)\n\ @@ -407,7 +420,7 @@ print_symname (const char *form, const char *name, bfd = *abfd) { if (do_demangle && *name) { - char *res =3D bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS); + char *res =3D bfd_demangle (abfd, name, demangle_flags); =20 if (res !=3D NULL) { @@ -1687,6 +1700,12 @@ main (int argc, char **argv) cplus_demangle_set_style (style); } break; + case OPTION_RECURSE_LIMIT: + demangle_flags |=3D DMGL_RECURSE_LIMIT; + break; + case OPTION_NO_RECURSE_LIMIT: + demangle_flags &=3D ~ DMGL_RECURSE_LIMIT; + break; case 'D': dynamic =3D 1; break; diff --git a/binutils/objdump.c b/binutils/objdump.c index 21f1284319..e0234232a4 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -120,6 +120,8 @@ static size_t prefix_length; static bfd_boolean unwind_inlines; /* --inlines. */ static const char * disasm_sym; /* Disassembly start symbol. */ =20 +static int demangle_flags =3D DMGL_ANSI | DMGL_PARAMS | DMGL_RECURSE_LIMIT; + /* A structure to record the sections mentioned in -j switches. */ struct only { @@ -252,6 +254,8 @@ usage (FILE *stream, int status) The STYLE, if specified, can be `auto', = `gnu',\n\ `lucid', `arm', `hp', `edg', `gnu-v3', `= java'\n\ or `gnat'\n\ + --recurse-limit Enable a limit on recursion whilst demang= ling. [Default]\n\ + --no-recurse-limit Disable a limit on recursion whilst deman= gling\n\ -w, --wide Format output for more than 80 columns\n\ -z, --disassemble-zeroes Do not skip blocks of zeroes when disasse= mbling\n\ --start-address=3DADDR Only process data whose address is >=3D= ADDR\n\ @@ -302,6 +306,8 @@ enum option_values OPTION_DWARF_DEPTH, OPTION_DWARF_CHECK, OPTION_DWARF_START, + OPTION_RECURSE_LIMIT, + OPTION_NO_RECURSE_LIMIT, OPTION_INLINES }; =20 @@ -333,6 +339,10 @@ static struct option long_options[]=3D {"line-numbers", no_argument, NULL, 'l'}, {"no-show-raw-insn", no_argument, &show_raw_insn, -1}, {"prefix-addresses", no_argument, &prefix_addresses, 1}, + {"recurse-limit", no_argument, NULL, OPTION_RECURSE_LIMIT}, + {"recursion-limit", no_argument, NULL, OPTION_RECURSE_LIMIT}, + {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, + {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT}, {"reloc", no_argument, NULL, 'r'}, {"section", required_argument, NULL, 'j'}, {"section-headers", no_argument, NULL, 'h'}, @@ -884,7 +894,7 @@ objdump_print_symname (bfd *abfd, struct disassemble_in= fo *inf, if (do_demangle && name[0] !=3D '\0') { /* Demangle the name. */ - alloc =3D bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS); + alloc =3D bfd_demangle (abfd, name, demangle_flags); if (alloc !=3D NULL) name =3D alloc; } @@ -2290,7 +2300,7 @@ disassemble_section (bfd *abfd, asection *section, vo= id *inf) if (do_demangle && name[0] !=3D '\0') { /* Demangle the name. */ - alloc =3D bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS); + alloc =3D bfd_demangle (abfd, name, demangle_flags); if (alloc !=3D NULL) name =3D alloc; } @@ -3268,7 +3278,7 @@ dump_symbols (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean= dynamic) /* If we want to demangle the name, we demangle it here, and temporarily clobber it while calling bfd_print_symbol. FIXME: This is a gross hack. */ - alloc =3D bfd_demangle (cur_bfd, name, DMGL_ANSI | DMGL_PARAMS); + alloc =3D bfd_demangle (cur_bfd, name, demangle_flags); if (alloc !=3D NULL) (*current)->name =3D alloc; bfd_print_symbol (cur_bfd, stdout, *current, @@ -3927,6 +3937,12 @@ main (int argc, char **argv) cplus_demangle_set_style (style); } break; + case OPTION_RECURSE_LIMIT: + demangle_flags |=3D DMGL_RECURSE_LIMIT; + break; + case OPTION_NO_RECURSE_LIMIT: + demangle_flags &=3D ~ DMGL_RECURSE_LIMIT; + break; case 'w': do_wide =3D wide_output =3D TRUE; break; diff --git a/binutils/prdbg.c b/binutils/prdbg.c index 4b9fa06c26..c981555521 100644 --- a/binutils/prdbg.c +++ b/binutils/prdbg.c @@ -286,6 +286,8 @@ static const struct debug_write_fns tg_fns =3D pr_end_function, /* Same, does nothing. */ tg_lineno }; + +static int demangle_flags =3D DMGL_ANSI | DMGL_PARAMS | DMGL_RECURSE_LIMIT; =0C /* Print out the generic debugging information recorded in dhandle. */ =20 @@ -2600,7 +2602,7 @@ tg_variable (void *p, const char *name, enum debug_va= r_kind kind, =20 dname =3D NULL; if (info->demangler) - dname =3D info->demangler (info->abfd, name, DMGL_ANSI | DMGL_PARAMS); + dname =3D info->demangler (info->abfd, name, demangle_flags); =20 from_class =3D NULL; if (dname !=3D NULL) @@ -2661,7 +2663,7 @@ tg_start_function (void *p, const char *name, bfd_boo= lean global) =20 dname =3D NULL; if (info->demangler) - dname =3D info->demangler (info->abfd, name, DMGL_ANSI | DMGL_PARAMS); + dname =3D info->demangler (info->abfd, name, demangle_flags); =20 if (! substitute_type (info, dname ? dname : name)) return FALSE; diff --git a/binutils/stabs.c b/binutils/stabs.c index bf53607560..dcd2aba57f 100644 --- a/binutils/stabs.c +++ b/binutils/stabs.c @@ -215,6 +215,8 @@ static debug_type stab_demangle_v3_arg (void *, struct stab_handle *, struct demangle_component *, debug_type, bfd_boolean *); =20 +static int demangle_flags =3D DMGL_ANSI | DMGL_RECURSE_LIMIT; + /* Save a string in memory. */ =20 static char * @@ -4517,7 +4519,7 @@ stab_demangle_template (struct stab_demangle_info *mi= nfo, const char **pp, =20 free (s1); =20 - s3 =3D cplus_demangle (s2, DMGL_ANSI); + s3 =3D cplus_demangle (s2, demangle_flags); =20 free (s2); =20 @@ -5243,7 +5245,7 @@ stab_demangle_v3_argtypes (void *dhandle, struct stab= _handle *info, void *mem; debug_type *pargs; =20 - dc =3D cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, = &mem); + dc =3D cplus_demangle_v3_components (physname, DMGL_PARAMS | demangle_fl= ags, &mem); if (dc =3D=3D NULL) { stab_bad_demangle (physname); @@ -5418,7 +5420,7 @@ stab_demangle_v3_arg (void *dhandle, struct stab_hand= le *info, /* We print this component to get a class name which we can use. FIXME: This probably won't work if the template uses template parameters which refer to an outer template. */ - p =3D cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc); + p =3D cplus_demangle_print (DMGL_PARAMS | demangle_flags, dc, 20, &alc); if (p =3D=3D NULL) { fprintf (stderr, _("Failed to print demangled template\n")); @@ -5498,7 +5500,7 @@ stab_demangle_v3_arg (void *dhandle, struct stab_hand= le *info, /* We print this component in order to find out the type name. FIXME: Should we instead expose the demangle_builtin_type_info structure? */ - p =3D cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc); + p =3D cplus_demangle_print (DMGL_PARAMS | demangle_flags, dc, 20, &alc); if (p =3D=3D NULL) { fprintf (stderr, _("Couldn't get demangled builtin type\n")); diff --git a/binutils/testsuite/config/default.exp b/binutils/testsuite/con= fig/default.exp index b34e45cd20..9ecfcf3e15 100644 --- a/binutils/testsuite/config/default.exp +++ b/binutils/testsuite/config/default.exp @@ -93,6 +93,12 @@ if ![info exists WINDRES] then { if ![info exists DLLTOOL] then { set DLLTOOL [findfile $base_dir/dlltool] } +if ![info exists CXXFILT] then { + set CXXFILT [findfile $base_dir/cxxfilt] +} +if ![info exists CXXFILTFLAGS] then { + set CXXFILTFLAGS "" +} =20 if ![file isdirectory tmpdir] {catch "exec mkdir tmpdir" status} =20 --- /dev/null 2018-11-29 08:15:54.667999248 +0000 +++ binutils/testsuite/binutils-all/cxxfilt.exp 2018-11-29 13:09:29.7891474= 47 +0000 @@ -0,0 +1,44 @@ +# Copyright (C) 2018 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +#=20 +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +#=20 +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-130= 1, USA. + +proc test_cxxfilt {options mangled_string demangled_string} { + global CXXFILT + global CXXFILTFLAGS +=20=20=20=20 + set testname "cxxfilt: demangling $mangled_string" + set got [binutils_run $CXXFILT "$options $CXXFILTFLAGS $mangled_string= "] + + if ![regexp $demangled_string $got] then { + fail "$testname" + verbose 0 "expected: $demangled_string" + return + } + + pass $testname +} + +# Mangled and demangled strings stolen from libiberty/testsuite/demangle-e= xpected. +test_cxxfilt {} \ + "AddAlignment__9ivTSolverUiP12ivInteractorP7ivTGlue" \ + "ivTSolver::AddAlignment(unsigned int, ivInteractor ., ivTGlue .)*" + +test_cxxfilt {--format=3Dlucid} \ + "__ct__12strstreambufFPFl_PvPFPv_v" \ + "strstreambuf..strstreambuf(void .(.)(long), void (.)(void .))*" + +test_cxxfilt {--recurse-limit=3D2} \ + "Z3fooiPiPS_PS0_PS1_PS2_PS3_PS4_PS5_PS6_PS7_PS8_PS9_PSA_PSB_PSC_" \ + "foo(int, int., int.., int..., int...., int....., int......, int......= ., int........, int........., int.........., int..........., int...........= ., int............., int.............., int...............)*" --------------40E57977C7277D321F77D8E0 Content-Type: text/x-patch; name="libiberty-demangler-recursion-limit.3.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="libiberty-demangler-recursion-limit.3.patch" Content-length: 6002 Index: libiberty/cp-demangle.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- libiberty/cp-demangle.c (revision 266657) +++ libiberty/cp-demangle.c (working copy) @@ -2852,21 +2852,35 @@ static struct demangle_component * d_function_type (struct d_info *di) { - struct demangle_component *ret; + struct demangle_component *ret =3D NULL; =20 - if (! d_check_char (di, 'F')) - return NULL; - if (d_peek_char (di) =3D=3D 'Y') + if (di->options & DMGL_RECURSE_LIMIT) { - /* Function has C linkage. We don't print this information. - FIXME: We should print it in verbose mode. */ - d_advance (di, 1); + if (di->recursion_level > DEMANGLE_RECURSION_LIMIT) + /* FIXME: There ought to be a way to report + that the recursion limit has been reached. */ + return NULL; + + di->recursion_level ++; } - ret =3D d_bare_function_type (di, 1); - ret =3D d_ref_qualifier (di, ret); =20 - if (! d_check_char (di, 'E')) - return NULL; + if (d_check_char (di, 'F')) + { + if (d_peek_char (di) =3D=3D 'Y') + { + /* Function has C linkage. We don't print this information. + FIXME: We should print it in verbose mode. */ + d_advance (di, 1); + } + ret =3D d_bare_function_type (di, 1); + ret =3D d_ref_qualifier (di, ret); +=20=20=20=20=20=20 + if (! d_check_char (di, 'E')) + ret =3D NULL; + } + + if (di->options & DMGL_RECURSE_LIMIT) + di->recursion_level --; return ret; } =20 @@ -6203,6 +6217,7 @@ di->expansion =3D 0; di->is_expression =3D 0; di->is_conversion =3D 0; + di->recursion_level =3D 0; } =20 /* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI @@ -6242,6 +6257,20 @@ =20 cplus_demangle_init_info (mangled, options, strlen (mangled), &di); =20 + /* PR 87675 - Check for a mangled string that is so long + that we do not have enough stack space to demangle it. */ + if ((options & DMGL_RECURSE_LIMIT) + /* This check is a bit arbitrary, since what we really want to do is= to + compare the sizes of the di.comps and di.subs arrays against the + amount of stack space remaining. But there is no portable way to do + this, so instead we use the recursion limit as a guide to the maximum + size of the arrays. */ + && (unsigned long) di.num_comps > DEMANGLE_RECURSION_LIMIT) + { + /* FIXME: We need a way to indicate that a stack limit has been reac= hed. */ + return 0; + } + { #ifdef CP_DYNAMIC_ARRAYS __extension__ struct demangle_component comps[di.num_comps]; Index: libiberty/cp-demangle.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- libiberty/cp-demangle.h (revision 266657) +++ libiberty/cp-demangle.h (working copy) @@ -122,6 +122,9 @@ /* Non-zero if we are parsing the type operand of a conversion operator, but not when in an expression. */ int is_conversion; + /* If DMGL_RECURSE_LIMIT is active then this is set to the + current recursion level. */ + unsigned int recursion_level; }; =20 /* To avoid running past the ending '\0', don't: Index: libiberty/cplus-dem.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- libiberty/cplus-dem.c (revision 266657) +++ libiberty/cplus-dem.c (working copy) @@ -146,6 +146,7 @@ int *proctypevec; /* Indices of currently processed remembered typev= ecs. */ int proctypevec_size; int nproctypes; + unsigned int recursion_level; }; =20 #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) @@ -4693,10 +4694,21 @@ demangle_nested_args (struct work_stuff *work, const char **mangled, string *declp) { + static unsigned long recursion_level =3D 0; string* saved_previous_argument; int result; int saved_nrepeats; =20 + if ((work->options & DMGL_RECURSE_LIMIT) + && work->recursion_level > DEMANGLE_RECURSION_LIMIT) + { + /* FIXME: There ought to be a way to report that the recursion limit + has been reached. */ + return 0; + } + + recursion_level ++; + /* The G++ name-mangling algorithm does not remember types on nested argument lists, unless -fsquangling is used, and in that case the type vector updated by remember_type is not used. So, we turn @@ -4723,6 +4735,7 @@ --work->forgetting_types; work->nrepeats =3D saved_nrepeats; =20 + --recursion_level; return result; } =20 Index: include/demangle.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- include/demangle.h (revision 266657) +++ include/demangle.h (working copy) @@ -68,6 +68,16 @@ /* If none of these are set, use 'current_demangling_style' as the default= . */ #define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DM= GL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST) =20 +/* Enable a limit on the depth of recursion in mangled strings. + Note if this limit is not enabled then stack exhaustion is possible when + demangling pathologically complicated strings. Bug reports about stack + exhaustion when the option is not enabled will be rejected. */=20=20 +#define DMGL_RECURSE_LIMIT (1 << 18)=09 + +/* If DMGL_RECURE_LIMIT is enabled, then this is the value + used as the maximum depth of recursion allowed. */ +#define DEMANGLE_RECURSION_LIMIT 1024 +=20=20 /* Enumeration of possible demangling styles. =20 Lucid and ARM styles are still kept logically distinct, even though --------------40E57977C7277D321F77D8E0--