From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by sourceware.org (Postfix) with ESMTPS id 503233857401; Tue, 25 May 2021 21:01:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 503233857401 Received: by mail-wr1-x42a.google.com with SMTP id x7so14015128wrt.12; Tue, 25 May 2021 14:01:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=FX/IUvEbm0/sTiD/Dwmw0eyPKJFtuD37WzJS5n/TIjE=; b=XidsUuadbhgTWE2KDZ19fI3Ayntd1EHyw+cNZLvf6irXz9cgkzh5cejhop591D/zzc yesVIlz4oFfIZhhJT14HxJpYpeNbilan+cFEblFj02kwrrmN2n8Lh4dOl23SHapdTBdf zcfKnxBB38HPDoBwCkFO0hyp57N0+DyoiQzl2nNXnkXBpT8hhzr05hrUW7GS5dFjSAOL Un49NLGU1sjARpyI4WSArf2CI+ljrrDgVU//WLzZHnAPGwq4SsG5/lCJVNY1t7wplnJM OQMLZAw85yAFvUrgJW0lhYGjJjz08iOqTFMpwVK5rWlumwrzQ/zS7RihUvRToWoyhwBZ k1EQ== X-Gm-Message-State: AOAM530F4FZjiF603jWKAjv8XyFfVTlcdZyhjAI3VVSQ/FYbHI2xcEDL 1d7EuKasSko+0+iR2TTPLXd7vdkDGlSUvQ== X-Google-Smtp-Source: ABdhPJzqt9U9rQ8vbXYS0XTYyfeHrB5GMIEmXRyjQqIEOLEAFAEcIltRi1BSe3qEPEuDaZsPET4fAA== X-Received: by 2002:adf:f58e:: with SMTP id f14mr29382480wro.258.1621976499025; Tue, 25 May 2021 14:01:39 -0700 (PDT) Received: from ?IPv6:2a01:e0a:1dc:b1c0:dc24:e2f9:5fda:13e2? ([2a01:e0a:1dc:b1c0:dc24:e2f9:5fda:13e2]) by smtp.googlemail.com with ESMTPSA id q27sm17362515wrz.79.2021.05.25.14.01.37 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 25 May 2021 14:01:38 -0700 (PDT) Subject: Re: [_GLIBCXX_DEBUG] Enhance rendering of assert message To: Jonathan Wakely Cc: "libstdc++@gcc.gnu.org" , gcc-patches References: <55ae3359-167f-7586-8195-b2ac5b1628e8@gmail.com> From: =?UTF-8?Q?Fran=c3=a7ois_Dumont?= Message-ID: <6e9705ca-518b-b535-4f5a-fc748306ec9e@gmail.com> Date: Tue, 25 May 2021 23:01:37 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.1 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/mixed; boundary="------------1681CE98AF31CC9031358412" Content-Language: fr X-Spam-Status: No, score=-10.2 required=5.0 tests=BAYES_00, BODY_8BITS, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, NICE_REPLY_A, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 25 May 2021 21:01:43 -0000 This is a multi-part message in MIME format. --------------1681CE98AF31CC9031358412 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit On 25/05/21 11:58 am, Jonathan Wakely wrote: > On 22/05/21 22:08 +0200, François Dumont via Libstdc++ wrote: >> Here is the part of the libbacktrace patch with the enhancement to >> the rendering of assert message. >> >> It only contains one real fix, the rendering of address. In 2 places >> it was done with "0x%p", so resulting in something like: 0x0x012345678 >> >> Otherwise it is just enhancements, mostly avoiding intermediate >> buffering. >> >> I am adding the _Parameter::_Named type to help on the rendering. I >> hesitated in doing the same for the _M_iterator type but eventually >> managed it with a template function. >> >>     libstdc++: [_GLIBCXX_DEBUG] Enhance rendering of assert message >> >>     Avoid building an intermediate buffer to print to stderr, push >> directly to stderr. >> >>     libstdc++-v3/ChangeLog: >> >>             * include/debug/formatter.h >>             (_Error_formatter::_Parameter::_Named): New. >>             (_Error_formatter::_Parameter::_Type): Inherit latter. >>             (_Error_formatter::_Parameter::_M_integer): Likewise. >>             (_Error_formatter::_Parameter::_M_string): Likewise. >>             * src/c++11/debug.cc: Include . >>             (_Print_func_t): New. >>             (print_raw(PrintContext&, const char*, ptrdiff_t)): New. >>             (print_word): Use '%.*s' format in fprintf to render only >> expected number of chars. >>             (pretty_print(PrintContext&, const char*, >> _Print_func_t)): New. >>             (print_type): Rename in... >>             (print_type_info): ...this. Use pretty_print. >>             (print_address, print_integer): New. >>             (print_named_name, print_iterator_constness, >> print_iterator_state): New. >>             (print_iterator_seq_type): New. >>             (print_named_field, print_type_field, >> print_instance_field, print_iterator_field): New. >>             (print_field): Use latters. >>             (print_quoted_named_name, print_type_type, print_type, >> print_instance): New. >>             (print_string(PrintContext&, const char*, const >> _Parameter*, size_t)): >>             Change signature to... >>             (print_string(PrintContext&, const char*, ptrdiff_t, >> const _Parameter*, size_t)): >>             ...this and adapt. Remove intermediate buffer to render >> input string. >>             (print_string(PrintContext&, const char*, ptrdiff_t)): New. >> >> Ok to commit ? >> >> François >> > >> +  void >> +  pretty_print(PrintContext& ctx, const char* str, _Print_func_t >> print_func) >> +  { >> +    const char cxx1998[] = "__cxx1998::"; >> +    const char uglification[] = "__"; >> +    for (;;) >> +      { >> +    auto idx = strstr(str, uglification); > > This is confusing. strstr returns a pointer, not an index into the > string. > >> +    if (idx) >> +      { >> +        size_t offset = >> +          (idx == strstr(str, cxx1998) >> +           ? sizeof(cxx1998) : sizeof(uglification)) - 1; > > This is a bit inefficient. Consider "int __foo(__cxx1998::bar)". The > first strstr returns a pointer to "__foo" and then the second one > searches the entire string from the beginning looking for > "__cxx1998::", and checks if it is the same position as "__foo". > > The second strstr doesn't need to search from the beginning, and it > doesn't need to look all the way to the end. It should be memcmp. > >       if (auto pos = strstr(str, uglification)) >         { >           if (pos != str) >             print_func(ctx, str, pos - str); > >           if (memcmp(pos, cxx1998, sizeof(cxx1998)-1) == 0) >             str = pos + (sizeof(cxx1998) - 1); >           else >             str = pos + (sizeof(uglification) - 1); >                       while (*str && isspace((unsigned char)*str)) >             ++str; > >           if (!*str) >             break; >         } >       else > > It doesn't even need to search from the position found by the first > strstr, because we already know it starts with "__", so: > >   for (;;) >     { >       if (auto pos = strstr(str, "__")) >         { >           if (pos != str) >             print_func(ctx, str, pos - str); > >           pos += 2; // advance past "__" > >           if (memcmp(pos, "cxx1998::", 9) == 0) >             str = pos + 9; // advance past "cxx1998::" >                       while (*str && isspace((unsigned char)*str)) >             ++str; > >           if (!*str) >             break; >         } >       else > > But either is OK. Just not doing a second strstr through the entire > string again to look for "__cxx1998::". > > > >> + >> +        if (idx != str) >> +          print_func(ctx, str, idx - str); >> + >> +        str = idx + offset; >> + >> +        while (*str && isspace((unsigned char)*str)) >> +          ++str; > > Is this really needed? > > Why would there be whitespace following "__" or "__cxx1998::" and why > would we want to skip it? Yes, I cannot remember why I added it in the first place. So removed in this new proposal with your other changes. > > I know it doesn't follow our usual naming scheme, but a symbol like > "__foo__ bar()" would get printed as "foobar()" wouldn't it? > Yes, it would. > The rest of the patch looks fine, I'm just unsure about pretty_print. > Maybe I've misunderstood the possible strings it gets used with? > pretty_print is used for demangle type names, variable names and function names given by the __PRETTY_FUNCTION__ macro. So in theory yes, __foo__bar would be replaced by foobar but I considered that we will never face this situation for the moment. When considering backtraces we might have to review this. Ok to commit ? François --------------1681CE98AF31CC9031358412 Content-Type: text/x-patch; charset=UTF-8; name="debug_mode.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="debug_mode.patch" diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h index 7140fed5e83..a83d33a4cb8 100644 --- a/libstdc++-v3/include/debug/formatter.h +++ b/libstdc++-v3/include/debug/formatter.h @@ -202,9 +202,13 @@ namespace __gnu_debug __iterator_value_type } _M_kind; - struct _Type + struct _Named { const char* _M_name; + }; + + struct _Type : _Named + { const type_info* _M_type; }; @@ -228,16 +232,14 @@ namespace __gnu_debug _Instance _M_sequence; // When _M_kind == __integer - struct + struct : _Named { - const char* _M_name; long _M_value; } _M_integer; // When _M_kind == __string - struct + struct : _Named { - const char* _M_name; const char* _M_value; } _M_string; diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index 5a642097d17..33d76bfcaab 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -34,16 +34,12 @@ #include #include -#include // for std::isspace +#include // for std::isspace. +#include // for std::strstr. -#include // for std::min +#include // for std::min. -#include // for __cxa_demangle - -// libstdc++/85768 -#if 0 // defined _GLIBCXX_HAVE_EXECINFO_H -# include // for backtrace -#endif +#include // for __cxa_demangle. #include "mutex_pool.h" @@ -574,7 +570,7 @@ namespace struct PrintContext { PrintContext() - : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false) + : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false) { get_max_length(_M_max_length); } std::size_t _M_max_length; @@ -584,16 +580,26 @@ namespace bool _M_wordwrap; }; + using _Print_func_t = void (PrintContext&, const char*, ptrdiff_t); + template void print_literal(PrintContext& ctx, const char(&word)[Length]) { print_word(ctx, word, Length - 1); } void - print_word(PrintContext& ctx, const char* word, - std::ptrdiff_t count = -1) + print_raw(PrintContext& ctx, const char* str, ptrdiff_t nbc = -1) { - size_t length = count >= 0 ? count : __builtin_strlen(word); + if (nbc >= 0) + ctx._M_column += fprintf(stderr, "%.*s", (int)nbc, str); + else + ctx._M_column += fprintf(stderr, "%s", str); + } + + void + print_word(PrintContext& ctx, const char* word, ptrdiff_t nbc = -1) + { + size_t length = nbc >= 0 ? nbc : __builtin_strlen(word); if (length == 0) return; @@ -610,7 +616,7 @@ namespace } size_t visual_length - = isspace(word[length - 1]) ? length - 1 : length; + = isspace((unsigned char)word[length - 1]) ? length - 1 : length; if (visual_length == 0 || !ctx._M_wordwrap || (ctx._M_column + visual_length < ctx._M_max_length) @@ -619,15 +625,11 @@ namespace // If this isn't the first line, indent if (ctx._M_column == 1 && !ctx._M_first_line) { - char spacing[ctx._M_indent + 1]; - for (int i = 0; i < ctx._M_indent; ++i) - spacing[i] = ' '; - spacing[ctx._M_indent] = '\0'; - fprintf(stderr, "%s", spacing); - ctx._M_column += ctx._M_indent; + const char spacing[ctx._M_indent + 1] = " "; + print_raw(ctx, spacing, ctx._M_indent); } - int written = fprintf(stderr, "%s", word); + int written = fprintf(stderr, "%.*s", (int)length, word); if (word[length - 1] == '\n') { @@ -640,15 +642,40 @@ namespace else { print_literal(ctx, "\n"); - print_word(ctx, word, count); + print_word(ctx, word, nbc); + } + } + + void + pretty_print(PrintContext& ctx, const char* str, _Print_func_t print_func) + { + const char cxx1998[] = "cxx1998::"; + for (;;) + { + if (auto pos = strstr(str, "__")) + { + if (pos != str) + print_func(ctx, str, pos - str); + + pos += 2; // advance past "__" + if (memcmp(pos, cxx1998, 9) == 0) + pos += 9; // advance part "cxx1998::" + + str = pos; + } + else + { + print_func(ctx, str, -1); + break; + } } } template void - print_type(PrintContext& ctx, - const type_info* info, - const char(&unknown_name)[Length]) + print_type_info(PrintContext& ctx, + const type_info* info, + const char(&unknown_name)[Length]) { if (!info) print_literal(ctx, unknown_name); @@ -657,22 +684,86 @@ namespace int status; char* demangled_name = __cxxabiv1::__cxa_demangle(info->name(), NULL, NULL, &status); - print_word(ctx, status == 0 ? demangled_name : info->name()); + if (status == 0) + pretty_print(ctx, demangled_name, &print_word); + else + print_word(ctx, info->name()); free(demangled_name); } } + void + print_address(PrintContext& ctx, const char* fmt, const void* address) + { + char buf[128]; + int written = __builtin_sprintf(buf, fmt, address); + print_word(ctx, buf, written); + } + + void + print_address(PrintContext& ctx, const void* address) + { print_address(ctx, "%p", address); } + + void + print_integer(PrintContext& ctx, long integer) + { + char buf[64]; + int written = __builtin_sprintf(buf, "%ld", integer); + print_word(ctx, buf, written); + } + + void + print_named_name(PrintContext& ctx, const _Parameter::_Named& named) + { + assert(named._M_name); + pretty_print(ctx, named._M_name, print_word); + } + + template + void + print_iterator_constness(PrintContext& ctx, const _Iterator& iterator) + { + static const char* + constness_names[_Error_formatter::__last_constness] = + { + "", + "constant", + "mutable" + }; + print_word(ctx, constness_names[iterator._M_constness]); + } + + template + void + print_iterator_state(PrintContext& ctx, const _Iterator& iterator) + { + static const char* + state_names[_Error_formatter::__last_state] = + { + "", + "singular", + "dereferenceable (start-of-sequence)", + "dereferenceable", + "past-the-end", + "before-begin", + "dereferenceable (start-of-reverse-sequence)", + "dereferenceable (reverse)", + "past-the-reverse-end" + }; + print_word(ctx, state_names[iterator._M_state]); + } + + template + void + print_iterator_seq_type(PrintContext& ctx, const _Iterator& iterator) + { print_type_info(ctx, iterator._M_seq_type, ""); } + bool - print_field(PrintContext& ctx, - const char* name, const _Parameter::_Type& type) + print_named_field(PrintContext& ctx, + const char* fname, const _Parameter::_Named& named) { - if (__builtin_strcmp(name, "name") == 0) - { - assert(type._M_name); - print_word(ctx, type._M_name); - } - else if (__builtin_strcmp(name, "type") == 0) - print_type(ctx, type._M_type, ""); + if (__builtin_strcmp(fname, "name") == 0) + print_named_name(ctx, named); else return false; @@ -680,112 +771,92 @@ namespace } bool - print_field(PrintContext& ctx, - const char* name, const _Parameter::_Instance& inst) + print_type_field(PrintContext& ctx, + const char* fname, const _Parameter::_Type& type) { - const _Parameter::_Type& type = inst; - if (print_field(ctx, name, type)) + if (print_named_field(ctx, fname, type)) { } - else if (__builtin_strcmp(name, "address") == 0) - { - char buf[64]; - int ret = __builtin_sprintf(buf, "%p", inst._M_address); - print_word(ctx, buf, ret); - } + else if (__builtin_strcmp(fname, "type") == 0) + print_type_info(ctx, type._M_type, ""); + else + return false; + + return true; + } + + bool + print_instance_field(PrintContext& ctx, + const char* fname, const _Parameter::_Instance& inst) + { + if (print_type_field(ctx, fname, inst)) + { } + else if (__builtin_strcmp(fname, "address") == 0) + print_address(ctx, inst._M_address); else return false; return true; } + template + bool + print_iterator_field(PrintContext& ctx, + const char* fname, const _Iterator& iterator) + { + if (print_instance_field(ctx, fname, iterator)) + { } + else if (__builtin_strcmp(fname, "constness") == 0) + print_iterator_constness(ctx, iterator); + else if (__builtin_strcmp(fname, "state") == 0) + print_iterator_state(ctx, iterator); + else if (__builtin_strcmp(fname, "sequence") == 0) + { + assert(iterator._M_sequence); + print_address(ctx, iterator._M_sequence); + } + else if (__builtin_strcmp(fname, "seq_type") == 0) + print_iterator_seq_type(ctx, iterator); + else + return false; + + return true; + } + void - print_field(PrintContext& ctx, const _Parameter& param, const char* name) + print_field(PrintContext& ctx, const _Parameter& param, const char* fname) { assert(param._M_kind != _Parameter::__unused_param); - const int bufsize = 64; - char buf[bufsize]; const auto& variant = param._M_variant; switch (param._M_kind) { case _Parameter::__iterator: - { - const auto& iterator = variant._M_iterator; - if (print_field(ctx, name, iterator)) - { } - else if (__builtin_strcmp(name, "constness") == 0) - { - static const char* - constness_names[_Error_formatter::__last_constness] = - { - "", - "constant", - "mutable" - }; - print_word(ctx, constness_names[iterator._M_constness]); - } - else if (__builtin_strcmp(name, "state") == 0) - { - static const char* - state_names[_Error_formatter::__last_state] = - { - "", - "singular", - "dereferenceable (start-of-sequence)", - "dereferenceable", - "past-the-end", - "before-begin", - "dereferenceable (start-of-reverse-sequence)", - "dereferenceable (reverse)", - "past-the-reverse-end" - }; - print_word(ctx, state_names[iterator._M_state]); - } - else if (__builtin_strcmp(name, "sequence") == 0) - { - assert(iterator._M_sequence); - int written = __builtin_sprintf(buf, "%p", iterator._M_sequence); - print_word(ctx, buf, written); - } - else if (__builtin_strcmp(name, "seq_type") == 0) - print_type(ctx, iterator._M_seq_type, ""); - else - assert(false); - } + if (!print_iterator_field(ctx, fname, variant._M_iterator)) + assert(false); break; case _Parameter::__sequence: - if (!print_field(ctx, name, variant._M_sequence)) + if (!print_instance_field(ctx, fname, variant._M_sequence)) assert(false); break; case _Parameter::__integer: - if (__builtin_strcmp(name, "name") == 0) - { - assert(variant._M_integer._M_name); - print_word(ctx, variant._M_integer._M_name); - } - else + if (!print_named_field(ctx, fname, variant._M_integer)) assert(false); break; case _Parameter::__string: - if (__builtin_strcmp(name, "name") == 0) - { - assert(variant._M_string._M_name); - print_word(ctx, variant._M_string._M_name); - } - else + if (!print_named_field(ctx, fname, variant._M_string)) assert(false); break; case _Parameter::__instance: - if (!print_field(ctx, name, variant._M_instance)) + if (!print_instance_field(ctx, fname, variant._M_instance)) assert(false); break; case _Parameter::__iterator_value_type: - if (!print_field(ctx, name, variant._M_iterator_value_type)) + if (!print_type_field(ctx, fname, variant._M_iterator_value_type)) assert(false); break; @@ -796,55 +867,53 @@ namespace } void - print_description(PrintContext& ctx, const _Parameter::_Type& type) + print_quoted_named_name(PrintContext& ctx, const _Parameter::_Named& named) { - if (type._M_name) + if (named._M_name) { print_literal(ctx, "\""); - print_word(ctx, type._M_name); - print_literal(ctx, "\""); + print_named_name(ctx, named); + print_literal(ctx, "\" "); } + } - print_literal(ctx, " {\n"); - + void + print_type_type(PrintContext& ctx, const _Parameter::_Type& type, + bool close_desc = true) + { if (type._M_type) { print_literal(ctx, " type = "); - print_type(ctx, type._M_type, ""); - print_literal(ctx, ";\n"); + print_type_info(ctx, type._M_type, ""); + if (close_desc) + print_literal(ctx, ";\n"); } } void - print_description(PrintContext& ctx, const _Parameter::_Instance& inst) + print_type(PrintContext& ctx, const _Parameter::_Type& type) { - const int bufsize = 64; - char buf[bufsize]; - - if (inst._M_name) - { - print_literal(ctx, "\""); - print_word(ctx, inst._M_name); - print_literal(ctx, "\" "); - } + print_quoted_named_name(ctx, type); + print_literal(ctx, " {\n"); + print_type_type(ctx, type); + print_literal(ctx, "}\n"); + } - int written - = __builtin_sprintf(buf, "@ 0x%p {\n", inst._M_address); - print_word(ctx, buf, written); + void + print_instance(PrintContext& ctx, const _Parameter::_Instance& inst, + bool close_desc = true) + { + print_quoted_named_name(ctx, inst); + print_address(ctx, "@ %p {\n", inst._M_address); + print_type_type(ctx, inst, close_desc); - if (inst._M_type) - { - print_literal(ctx, " type = "); - print_type(ctx, inst._M_type, ""); - } + if (close_desc) + print_literal(ctx, "}\n"); } void print_description(PrintContext& ctx, const _Parameter& param) { - const int bufsize = 128; - char buf[bufsize]; - const auto& variant = param._M_variant; switch (param._M_kind) { @@ -853,14 +922,14 @@ namespace const auto& ite = variant._M_iterator; print_literal(ctx, "iterator "); - print_description(ctx, ite); + print_instance(ctx, ite, false); if (ite._M_type) { if (ite._M_constness != _Error_formatter::__unknown_constness) { print_literal(ctx, " ("); - print_field(ctx, param, "constness"); + print_iterator_constness(ctx, ite); print_literal(ctx, " iterator)"); } @@ -870,7 +939,7 @@ namespace if (ite._M_state != _Error_formatter::__unknown_state) { print_literal(ctx, " state = "); - print_field(ctx, param, "state"); + print_iterator_state(ctx, ite); print_literal(ctx, ";\n"); } @@ -880,13 +949,11 @@ namespace if (ite._M_seq_type) { print_literal(ctx, "with type '"); - print_field(ctx, param, "seq_type"); + print_iterator_seq_type(ctx, ite); print_literal(ctx, "' "); } - int written - = __builtin_sprintf(buf, "@ 0x%p\n", ite._M_sequence); - print_word(ctx, buf, written); + print_address(ctx, "@ %p\n", ite._M_sequence); } print_literal(ctx, "}\n"); @@ -895,28 +962,17 @@ namespace case _Parameter::__sequence: print_literal(ctx, "sequence "); - print_description(ctx, variant._M_sequence); - - if (variant._M_sequence._M_type) - print_literal(ctx, ";\n"); - - print_literal(ctx, "}\n"); + print_instance(ctx, variant._M_sequence); break; case _Parameter::__instance: print_literal(ctx, "instance "); - print_description(ctx, variant._M_instance); - - if (variant._M_instance._M_type) - print_literal(ctx, ";\n"); - - print_literal(ctx, "}\n"); + print_instance(ctx, variant._M_instance); break; case _Parameter::__iterator_value_type: print_literal(ctx, "iterator::value_type "); - print_description(ctx, variant._M_iterator_value_type); - print_literal(ctx, "}\n"); + print_type(ctx, variant._M_iterator_value_type); break; default: @@ -925,71 +981,67 @@ namespace } void - print_string(PrintContext& ctx, const char* string, + print_string(PrintContext& ctx, const char* str, ptrdiff_t nbc, const _Parameter* parameters, std::size_t num_parameters) { - const char* start = string; - const int bufsize = 128; - char buf[bufsize]; - int bufindex = 0; + const char* start = str; + const char* end = nbc >= 0 ? start + nbc : nullptr; - while (*start) + while ((end && str != end) || (!end && *str)) { - if (isspace(*start)) + if (isspace((unsigned char)*str)) { - buf[bufindex++] = *start++; - buf[bufindex] = '\0'; - print_word(ctx, buf, bufindex); - bufindex = 0; + ++str; + print_word(ctx, start, str - start); + start = str; continue; } - if (!num_parameters || *start != '%') + if (!parameters || *str != '%') { // Normal char or no parameter to look for. - buf[bufindex++] = *start++; + ++str; continue; } - if (*++start == '%') + if (*++str == '%') { // Escaped '%' - buf[bufindex++] = *start++; + print_word(ctx, start, str - start); + ++str; + start = str; continue; } // We are on a parameter property reference, we need to flush buffer // first. - if (bufindex != 0) + if (str != start) { - buf[bufindex] = '\0'; - print_word(ctx, buf, bufindex); - bufindex = 0; + // Avoid printing the '%'. + if (str - start > 1) + print_word(ctx, start, str - start - 1); + start = str; } // Get the parameter number - assert(*start >= '1' && *start <= '9'); - size_t param_index = *start - '0' - 1; + assert(*str >= '1' && *str <= '9'); + size_t param_index = *str - '0' - 1; assert(param_index < num_parameters); const auto& param = parameters[param_index]; // '.' separates the parameter number from the field // name, if there is one. - ++start; - if (*start != '.') + ++str; + if (*str != '.') { - assert(*start == ';'); - ++start; + assert(*str == ';'); + ++str; if (param._M_kind == _Parameter::__integer) - { - int written - = __builtin_sprintf(buf, "%ld", - param._M_variant._M_integer._M_value); - print_word(ctx, buf, written); - } + print_integer(ctx, param._M_variant._M_integer._M_value); else if (param._M_kind == _Parameter::__string) - print_string(ctx, param._M_variant._M_string._M_value, + print_string(ctx, param._M_variant._M_string._M_value, -1, parameters, num_parameters); + start = str; continue; } @@ -997,26 +1049,28 @@ namespace const int max_field_len = 16; char field[max_field_len]; int field_idx = 0; - ++start; - while (*start != ';') + ++str; + while (*str != ';') { - assert(*start); + assert(*str); assert(field_idx < max_field_len - 1); - field[field_idx++] = *start++; + field[field_idx++] = *str++; } - ++start; + ++str; field[field_idx] = '\0'; print_field(ctx, param, field); + start = str; } // Might need to flush. - if (bufindex) - { - buf[bufindex] = '\0'; - print_word(ctx, buf, bufindex); - } + if (str != start) + print_word(ctx, start, str - start); } + + void + print_string(PrintContext& ctx, const char* str, ptrdiff_t nbc) + { print_string(ctx, str, nbc, nullptr, 0); } } namespace __gnu_debug @@ -1036,16 +1090,15 @@ namespace __gnu_debug PrintContext ctx; if (_M_file) { - print_word(ctx, _M_file); + print_raw(ctx, _M_file); print_literal(ctx, ":"); go_to_next_line = true; } if (_M_line > 0) { - char buf[64]; - int written = __builtin_sprintf(buf, "%u:", _M_line); - print_word(ctx, buf, written); + ctx._M_column += fprintf(stderr, "%u", _M_line); + print_literal(ctx, ":"); go_to_next_line = true; } @@ -1058,41 +1111,17 @@ namespace __gnu_debug if (_M_function) { print_literal(ctx, "In function:\n"); - print_string(ctx, _M_function, nullptr, 0); + pretty_print(ctx, _M_function, &print_string); print_literal(ctx, "\n"); ctx._M_first_line = true; print_literal(ctx, "\n"); } -// libstdc++/85768 -#if 0 //defined _GLIBCXX_HAVE_EXECINFO_H - { - void* stack[32]; - int nb = backtrace(stack, 32); - - // Note that we skip current method symbol. - if (nb > 1) - { - print_literal(ctx, "Backtrace:\n"); - auto symbols = backtrace_symbols(stack, nb); - for (int i = 1; i < nb; ++i) - { - print_word(ctx, symbols[i]); - print_literal(ctx, "\n"); - } - - free(symbols); - ctx._M_first_line = true; - print_literal(ctx, "\n"); - } - } -#endif - print_literal(ctx, "Error: "); // Print the error message assert(_M_text); - print_string(ctx, _M_text, _M_parameters, _M_num_parameters); + print_string(ctx, _M_text, -1, _M_parameters, _M_num_parameters); print_literal(ctx, ".\n"); // Emit descriptions of the objects involved in the operation --------------1681CE98AF31CC9031358412--