diff mbox

[i386] : Fix PR 67484, asan detects heap-use-after-free with target options

Message ID CAFULd4bj2PTRvDbbRYwdxjGHc7fETB1-8jV1GW8Zio2Ae_Vdpw@mail.gmail.com
State New
Headers show

Commit Message

Uros Bizjak Sept. 15, 2015, 6:13 p.m. UTC
Hello!

As mentioned in the PR, ix86_valid_target_attribute_tree creates
temporary copies of current options strings and saves *pointers* to
these copies with build_target_option_node. A couple of lines below,
these temporary copies are freed, leaving dangling pointers in the
saved structure.

Use xstrndup to create permanent copy of string on the heap. This will
however create a small leak, as this copy is never deallocated.

There is no test infrastructure to check for memory errors, so there
is no testcase added.

2015-09-15  Uros Bizjak  <ubizjak@gmail.com>

    PR target/67484
    * config/i386/i386.c (ix86_valid_target_attribute_tree):
    Use xstrdup to copy option_strings to opts->x_ix86_arch_string and
    opts->x_ix86_tune_string.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

I'll wait a couple of days for possible comments on the above solution.

Uros.

Comments

Richard Biener Sept. 16, 2015, 8:45 a.m. UTC | #1
On Tue, Sep 15, 2015 at 8:13 PM, Uros Bizjak <ubizjak@gmail.com> wrote:
> Hello!
>
> As mentioned in the PR, ix86_valid_target_attribute_tree creates
> temporary copies of current options strings and saves *pointers* to
> these copies with build_target_option_node. A couple of lines below,
> these temporary copies are freed, leaving dangling pointers in the
> saved structure.
>
> Use xstrndup to create permanent copy of string on the heap. This will
> however create a small leak, as this copy is never deallocated.
>
> There is no test infrastructure to check for memory errors, so there
> is no testcase added.
>
> 2015-09-15  Uros Bizjak  <ubizjak@gmail.com>
>
>     PR target/67484
>     * config/i386/i386.c (ix86_valid_target_attribute_tree):
>     Use xstrdup to copy option_strings to opts->x_ix86_arch_string and
>     opts->x_ix86_tune_string.
>
> Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
>
> I'll wait a couple of days for possible comments on the above solution.

I thought we have a custom destructor for target_option_node.  Ah, no,
that was for target_globals.  I suppose we could add one to cl_target_option
as well.  Note that currently the strings are not GTY((skip)) so it seems
we expect ggc allocated strings there?  Which means the xstrdup in
ix86_valid_target_attribute_inner_p should be ggc_strdup?

Richard.

> Uros.
Uros Bizjak Sept. 16, 2015, 8:59 a.m. UTC | #2
On Wed, Sep 16, 2015 at 10:45 AM, Richard Biener
<richard.guenther@gmail.com> wrote:

>> As mentioned in the PR, ix86_valid_target_attribute_tree creates
>> temporary copies of current options strings and saves *pointers* to
>> these copies with build_target_option_node. A couple of lines below,
>> these temporary copies are freed, leaving dangling pointers in the
>> saved structure.
>>
>> Use xstrndup to create permanent copy of string on the heap. This will
>> however create a small leak, as this copy is never deallocated.
>>
>> There is no test infrastructure to check for memory errors, so there
>> is no testcase added.
>>
>> 2015-09-15  Uros Bizjak  <ubizjak@gmail.com>
>>
>>     PR target/67484
>>     * config/i386/i386.c (ix86_valid_target_attribute_tree):
>>     Use xstrdup to copy option_strings to opts->x_ix86_arch_string and
>>     opts->x_ix86_tune_string.
>>
>> Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
>>
>> I'll wait a couple of days for possible comments on the above solution.
>
> I thought we have a custom destructor for target_option_node.  Ah, no,
> that was for target_globals.  I suppose we could add one to cl_target_option
> as well.  Note that currently the strings are not GTY((skip)) so it seems
> we expect ggc allocated strings there?  Which means the xstrdup in
> ix86_valid_target_attribute_inner_p should be ggc_strdup?

This is a bit over my knowledge of option processing, but please note
that the only function that performs non-recursive call to
ix86_valid_target_attribute_inner_p also frees the strings, allocated
by mentioned function.

Uros.
Richard Biener Sept. 16, 2015, 9:08 a.m. UTC | #3
I see in gtype-desc.c:

void
gt_ggc_mx_cl_target_option (void *x_p)
{
  struct cl_target_option * const x = (struct cl_target_option *)x_p;
  if (ggc_test_and_set_mark (x))
    {
      gt_ggc_m_S ((*x).x_ix86_arch_string);
      gt_ggc_m_S ((*x).x_ix86_recip_name);
      gt_ggc_m_S ((*x).x_ix86_tune_ctrl_string);
      gt_ggc_m_S ((*x).x_ix86_tune_memcpy_strategy);
      gt_ggc_m_S ((*x).x_ix86_tune_memset_strategy);
      gt_ggc_m_S ((*x).x_ix86_tune_string);
    }

so it certainly does not expect heap allocated strings in
ix86_arch_string and friends.

Richard.

On Wed, Sep 16, 2015 at 10:59 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
> On Wed, Sep 16, 2015 at 10:45 AM, Richard Biener
> <richard.guenther@gmail.com> wrote:
>
>>> As mentioned in the PR, ix86_valid_target_attribute_tree creates
>>> temporary copies of current options strings and saves *pointers* to
>>> these copies with build_target_option_node. A couple of lines below,
>>> these temporary copies are freed, leaving dangling pointers in the
>>> saved structure.
>>>
>>> Use xstrndup to create permanent copy of string on the heap. This will
>>> however create a small leak, as this copy is never deallocated.
>>>
>>> There is no test infrastructure to check for memory errors, so there
>>> is no testcase added.
>>>
>>> 2015-09-15  Uros Bizjak  <ubizjak@gmail.com>
>>>
>>>     PR target/67484
>>>     * config/i386/i386.c (ix86_valid_target_attribute_tree):
>>>     Use xstrdup to copy option_strings to opts->x_ix86_arch_string and
>>>     opts->x_ix86_tune_string.
>>>
>>> Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
>>>
>>> I'll wait a couple of days for possible comments on the above solution.
>>
>> I thought we have a custom destructor for target_option_node.  Ah, no,
>> that was for target_globals.  I suppose we could add one to cl_target_option
>> as well.  Note that currently the strings are not GTY((skip)) so it seems
>> we expect ggc allocated strings there?  Which means the xstrdup in
>> ix86_valid_target_attribute_inner_p should be ggc_strdup?
>
> This is a bit over my knowledge of option processing, but please note
> that the only function that performs non-recursive call to
> ix86_valid_target_attribute_inner_p also frees the strings, allocated
> by mentioned function.
>
> Uros.
Richard Biener Sept. 16, 2015, 9:15 a.m. UTC | #4
And it is initialized via

void
cl_target_option_save (struct cl_target_option *ptr, struct gcc_options *opts)
{
  if (targetm.target_option.save)
    targetm.target_option.save (ptr, opts);

  ptr->x_recip_mask = opts->x_recip_mask;
  ptr->x_ix86_isa_flags = opts->x_ix86_isa_flags;
  ptr->x_ix86_fpmath = opts->x_ix86_fpmath;
  ptr->x_target_flags = opts->x_target_flags;
}

which uses a target hook to copy from gcc_options to cl_target_options...
(what a maze), and ix86_function_specific_save also plain copies the
pointers.

Richard.

On Wed, Sep 16, 2015 at 11:08 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> I see in gtype-desc.c:
>
> void
> gt_ggc_mx_cl_target_option (void *x_p)
> {
>   struct cl_target_option * const x = (struct cl_target_option *)x_p;
>   if (ggc_test_and_set_mark (x))
>     {
>       gt_ggc_m_S ((*x).x_ix86_arch_string);
>       gt_ggc_m_S ((*x).x_ix86_recip_name);
>       gt_ggc_m_S ((*x).x_ix86_tune_ctrl_string);
>       gt_ggc_m_S ((*x).x_ix86_tune_memcpy_strategy);
>       gt_ggc_m_S ((*x).x_ix86_tune_memset_strategy);
>       gt_ggc_m_S ((*x).x_ix86_tune_string);
>     }
>
> so it certainly does not expect heap allocated strings in
> ix86_arch_string and friends.
>
> Richard.
>
> On Wed, Sep 16, 2015 at 10:59 AM, Uros Bizjak <ubizjak@gmail.com> wrote:
>> On Wed, Sep 16, 2015 at 10:45 AM, Richard Biener
>> <richard.guenther@gmail.com> wrote:
>>
>>>> As mentioned in the PR, ix86_valid_target_attribute_tree creates
>>>> temporary copies of current options strings and saves *pointers* to
>>>> these copies with build_target_option_node. A couple of lines below,
>>>> these temporary copies are freed, leaving dangling pointers in the
>>>> saved structure.
>>>>
>>>> Use xstrndup to create permanent copy of string on the heap. This will
>>>> however create a small leak, as this copy is never deallocated.
>>>>
>>>> There is no test infrastructure to check for memory errors, so there
>>>> is no testcase added.
>>>>
>>>> 2015-09-15  Uros Bizjak  <ubizjak@gmail.com>
>>>>
>>>>     PR target/67484
>>>>     * config/i386/i386.c (ix86_valid_target_attribute_tree):
>>>>     Use xstrdup to copy option_strings to opts->x_ix86_arch_string and
>>>>     opts->x_ix86_tune_string.
>>>>
>>>> Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
>>>>
>>>> I'll wait a couple of days for possible comments on the above solution.
>>>
>>> I thought we have a custom destructor for target_option_node.  Ah, no,
>>> that was for target_globals.  I suppose we could add one to cl_target_option
>>> as well.  Note that currently the strings are not GTY((skip)) so it seems
>>> we expect ggc allocated strings there?  Which means the xstrdup in
>>> ix86_valid_target_attribute_inner_p should be ggc_strdup?
>>
>> This is a bit over my knowledge of option processing, but please note
>> that the only function that performs non-recursive call to
>> ix86_valid_target_attribute_inner_p also frees the strings, allocated
>> by mentioned function.
>>
>> Uros.
diff mbox

Patch

Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 227777)
+++ config/i386/i386.c	(working copy)
@@ -5080,12 +5080,14 @@  ix86_valid_target_attribute_tree (tree args,
       /* If we are using the default tune= or arch=, undo the string assigned,
 	 and use the default.  */
       if (option_strings[IX86_FUNCTION_SPECIFIC_ARCH])
-	opts->x_ix86_arch_string = option_strings[IX86_FUNCTION_SPECIFIC_ARCH];
+	opts->x_ix86_arch_string
+	  = xstrdup (option_strings[IX86_FUNCTION_SPECIFIC_ARCH]);
       else if (!orig_arch_specified)
 	opts->x_ix86_arch_string = NULL;
 
       if (option_strings[IX86_FUNCTION_SPECIFIC_TUNE])
-	opts->x_ix86_tune_string = option_strings[IX86_FUNCTION_SPECIFIC_TUNE];
+	opts->x_ix86_tune_string
+	  = xstrdup (option_strings[IX86_FUNCTION_SPECIFIC_TUNE]);
       else if (orig_tune_defaulted)
 	opts->x_ix86_tune_string = NULL;