On February 12, 2021 7:21:25 PM GMT+01:00, Martin Sebor <mse...@gmail.com> 
wrote:
>On 2/12/21 12:35 AM, Richard Biener wrote:
>> On Thu, Feb 11, 2021 at 7:35 PM Martin Sebor <mse...@gmail.com>
>wrote:
>>>
>>> On 2/11/21 12:59 AM, Richard Biener wrote:
>>>> On Wed, Feb 10, 2021 at 6:16 PM Martin Sebor <mse...@gmail.com>
>wrote:
>>>>>
>>>>> The attached patch replaces calls to print_generic_expr_to_str()
>with
>>>>> a helper function that returns a std::string and releases the
>caller
>>>>> from the responsibility to explicitly free memory.
>>>>
>>>> I don't like this.  What's the reason to use generic_expr_as_string
>>>> anyway?  We have %E pretty-printers after all.
>>>
>>> [Reposting; my first reply was too big.]
>>>
>>> The VLA bound is either an expression or the asterisk (*) when
>newbnd
>>> is null.  The reason for using the function is to avoid duplicating
>>> the warning call and making one with %E and another with "*".
>>>
>>>> Couldn't you have
>>>> fixed the leak by doing
>>>>
>>>> if (newbnd)
>>>>     free (newbndstr);
>>>>
>>>> etc.?
>>>
>>> Yes, I could have.  I considered it and chose not to because this
>>> is much simpler, safer (if newbnd were to change after newbndstr
>>> is set), and more in the "C++ spirit" (RAII).  This code already
>>> uses std::string (attr_access::array_as_string) and so my change
>>> is in line with it.
>>>
>>> I understand that you prefer a more C-ish coding style so if you
>>> consider it a prerequisite for accepting this fix I can make
>>> the change conform to it.  See the attached revision (although
>>> I hope you'll see why I chose not to go this route).
>> 
>> I can understand but I still disagree ;)
>> 
>>> For what it's worth, print_generic_expr_to_str() would be improved
>>> by returning std::string.  It would mean including <string> in
>>> most sources in the compiler, which I suspect may not be a popular
>>> suggestion with everyone here, and which is why I didn't make it
>>> to begin with.  But if you're open to it I'm happy to make that
>>> change either for GCC 12 or even now.
>> 
>> Well, looking at print_generic_expr_to_str I see
>> 
>> /* Print a single expression T to string, and return it.  */
>> 
>> char *
>> print_generic_expr_to_str (tree t)
>> {
>>    pretty_printer pp;
>>    dump_generic_node (&pp, t, 0, TDF_VOPS|TDF_MEMSYMS, false);
>>    return xstrdup (pp_formatted_text (&pp));
>> }
>> 
>> which makes me think that this instead should be sth like
>> 
>> class generic_expr_as_str : public pretty_printer
>> {
>>     generic_expr_as_str (tree t) { dump_generic_node (&pp, t, 0,
>> TDF_VOPS|TDF_MEMSYMS, false); }
>>     operator const char *() { return pp_formatted_text (&pp); }
>>     pretty_printer pp;
>> };
>
>This wouldn't be a good general solution either (in fact, I'd say
>it would make it worse) because the string's lifetime is tied to
>the lifetime of the class object, turning memory leaks to uses-
>after-free.  Consider:
>
>   const char *str = generic_expr_as_str (node);
>   ...
>   warning ("node = %s", str);   // str is dangling/invalid
>
>(Trying to "fix" it by replacing the conversion operator with a named
>member function like str() doesn't solve the problem.)

But the issue with std::string is that people will have to use .c_str() because 
of the gazillion C style interfaces in GCC
and storage of std::string will eventually lead to lots of copying or use the 
other very same use after free or leak issues. 

std::string isn't the great solution you are presenting it as. 

Richard. 

>> 
>> As we do seem to have a RAII pretty-printer class already.  That
>said,
>> I won't mind using
>> 
>>     pretty_printer pp;
>>     dump_generic_node (&pp, t, 0, TDF_VOPS|TDF_MEMSYMS, false);
>> 
>> and pp_formatted_text () in the users either.
>
>Okay.
>
>> 
>> That is, print_generic_expr_to_str looks just like a bad designed
>hack.
>> Using std::string there doesn't make it any better.
>> 
>> Don't you agree to that?
>
>I agree that print_generic_expr_to_str() could be improved.  But
>a simple API that returns a string representation of a tree node
>needs to be easy to use safely and correctly and hard to misuse.
>It shouldn't require its clients to explicitly manage the lifetimes
>of multiple objects.
>
>But this isn't a new problem, and the solution is as old as C++
>itself: have the API return an object of an RAII class like
>std::string, or more generally something like std::unique_ptr.
>In this case it could even be GCC's auto_vec<char*>, or (less
>user-friendly) a garbage collected STRING_CST.
>
>> 
>> So your 2nd variant patch is OK but you might consider just using
>> a pretty-printer manually and even do away with the xstrdup in that
>> way entirely!
>
>Avoiding the xstrdup sounds good to me.  I've changed the code to
>use the pretty_printer directly and committed the attached patch.
>
>Martin
>
>> 
>>>>
>>>>> With the patch installed, Valgrind shows more leaks in this code
>that
>>>>> I'm not sure what to do about:
>>>>>
>>>>> 1) A tree built by build_type_attribute_qual_variant() called from
>>>>>       attr_access::array_as_string() to build a temporary type
>only
>>>>>       for the purposes of formatting it.
>>>>>
>>>>> 2) A tree (an attribute list) built by tree_cons() called from
>>>>>       build_attr_access_from_parms() that's used only for the
>duration
>>>>>       of the caller.
>>>>>
>>>>> Do these temporary trees need to be released somehow or are the
>leaks
>>>>> expected?
>>>>
>>>> You should configure GCC with --enable-valgrind-annotations to make
>>>> it aware of our GC.
>>>
>>> I did configure with that option:
>>>
>>> $ /src/gcc/master/configure --enable-checking=yes
>>> --enable-languages=all,jit,lto --enable-host-shared
>>> --enable-valgrind-annotations
>>>
>>> Attached to pr99055 is my valgrind output for
>gcc.dg/Wvla-parameter.c
>>> with the top of trunk and the patch applied:
>>>
>>> $ /build/gcc-master/gcc/xgcc -B /build/gcc-master/gcc -S -Wall
>>> /src/gcc/master/gcc/testsuite/gcc.dg/Wvla-parameter.c -wrapper
>>>
>valgrind,--leak-check=full,--show-leak-kinds=all,--track-origins=yes,--log-file=valgrind-out.txt
>>>
>>> Do you not see the same leaks?
>> 
>> Err, well.  --show-leak-kinds=all is probably the cause.  We
>> definitely do not force-release
>> all reachable GC allocated memory at program end.  Not sure if
>> valgrind annotations can
>> make that obvious to valgrind.  I'm just using --leak-check=full and
>> thus look for
>> unreleased and no longer reachable memory.
>> 
>> Richard.
>> 
>>>
>>> Martin
>>>

Reply via email to