public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Maxim Ostapenko <m.ostapenko@samsung.com>
To: Jakub Jelinek <jakub@redhat.com>, Jan Hubicka <hubicka@ucw.cz>,
	Richard Biener <rguenther@suse.de>
Cc: GCC Patches <gcc-patches@gcc.gnu.org>,
	Yury Gribov <y.gribov@samsung.com>,
	Slava Garbuzov <v.garbuzov@samsung.com>
Subject: Re: [PATCH][PR sanitizer/70541] Fix unnoticed invalid dereference when using AddressSanitizer.
Date: Fri, 08 Apr 2016 10:51:00 -0000	[thread overview]
Message-ID: <57078D0B.5050703@samsung.com> (raw)
In-Reply-To: <20160408091238.GP19207@tucnak.redhat.com>

[-- Attachment #1: Type: text/plain, Size: 3913 bytes --]

On 08/04/16 12:12, Jakub Jelinek wrote:
> On Fri, Apr 08, 2016 at 11:52:32AM +0300, Maxim Ostapenko wrote:
>> 2016-04-08  Maxim Ostapenko  <m.ostapenko@samsung.com>
>>
>> 	PR sanitizer/70541
>> 	* asan.c (instrument_derefs): If we get unknown location, extract it
>> 	with EXPR_LOCATION.
>> 	(maybe_instrument_call): Instrument gimple_call's arguments if needed.
>> 	* tree-inline.c (initialize_inlined_parameters): Set location for
>> 	inlined parameters initialization statements.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 2016-04-08  Maxim Ostapenko  <m.ostapenko@samsung.com>
>>
>> 	PR sanitizer/70541
>> 	* c-c++-common/asan/pr70541-1.c: New test.
>> 	* c-c++-common/pr70541-2.c: Likewise.
>> +  /* Walk through gimple_call arguments and check them id needed.  */
>> +  unsigned args_num = gimple_call_num_args (stmt);
>> +  for (unsigned i = 0; i < args_num; ++i)
>> +    {
>> +      tree arg = gimple_call_arg (stmt, i);
>> +      gcc_assert (TREE_CODE (arg) != CALL_EXPR);
> Please remove this assert, of course in GIMPLE arguments can't be
> CALL_EXPRs, they must satisfy is_gimple_val or is_gimple_lvalue, but
> that is verified in verify_gimple_call.
>
>> +      /* If ARG is not a non-aggregate register variable, compiler in general
>> +	 creates temporary for it and pass it as argument to gimple call.
>> +	 But in some cases, e.g. when we pass by value a small structure that
>> +	 fits to register, compiler can avoid extra overhead by pulling out
>> +	 these temporaries.  In this case, we should check the argument.  */
>> +      if (!is_gimple_reg (arg))
> Actually, I believe this should be
>        if (!is_gimple_reg (arg) && !is_gimple_min_invariant (arg))
> because constants, or addresses etc. also aren't memory references.
> I know instrument_derefs exits early if the t isn't one of the selected
> few trees, but still, it looks unclean to call instrument_derefs on
> constants or addresses.
>
> The asan.c changes look good to me with those changes, feel free to commit
> them separately from the tree-inline.c change (perhaps with something in the
> testcase XFAILed for now).

Ok, thanks, landed ASan part as r234827. I'm not sure how to XFAIL 
output pattern tests only, so I enabled testcase only with -O0 for now.

>
>> --- a/gcc/tree-inline.c
>> +++ b/gcc/tree-inline.c
>> @@ -3247,7 +3247,8 @@ initialize_inlined_parameters (copy_body_data *id, gimple *stmt,
>>       {
>>         tree val;
>>         val = i < gimple_call_num_args (stmt) ? gimple_call_arg (stmt, i) : NULL;
>> -      setup_one_parameter (id, p, val, fn, bb, &vars);
>> +      if (gimple *new_stmt = setup_one_parameter (id, p, val, fn, bb, &vars))
>> +	gimple_set_location (new_stmt, gimple_location (stmt));
>>       }
>>     /* After remapping parameters remap their types.  This has to be done
>>        in a second loop over all parameters to appropriately remap
>> @@ -3285,7 +3286,9 @@ initialize_inlined_parameters (copy_body_data *id, gimple *stmt,
>>         /* No static chain?  Seems like a bug in tree-nested.c.  */
>>         gcc_assert (static_chain);
>>   
>> -      setup_one_parameter (id, p, static_chain, fn, bb, &vars);
>> +      if (gimple *new_stmt = setup_one_parameter (id, p, static_chain, fn, bb,
>> +						  &vars))
>> +	gimple_set_location (new_stmt, gimple_location (stmt));
>>       }
>>   
>>     declare_inline_vars (id->block, vars);
> The tree-inline.c change looks much more risky at this point, could we defer
> that for GCC 7?    Unlike the asan change this is going to affect debugging, etc.
> Maybe e.g. pass gimple_location (stmt) as argument to setup_one_parameter
> and set it in there instead?  Sometimes there are multiple statements
> created in there, not just one, etc.  In any case, I'd prefer second pair of
> eyes on the tree-inline.c changes, so I'm CCing Richi and Honza.

Perhaps we should move this issue to separate bug in Bugzilla?

>
> 	Jakub
>
>

-Maxim

[-- Attachment #2: pr70541-2.diff --]
[-- Type: text/x-diff, Size: 3899 bytes --]

gcc/ChangeLog:

2016-04-08  Maxim Ostapenko  <m.ostapenko@samsung.com>

	PR sanitizer/70541
	* asan.c (instrument_derefs): If we get unknown location, extract it
	with EXPR_LOCATION.
	(maybe_instrument_call): Instrument gimple_call's arguments if needed.

gcc/testsuite/ChangeLog:

2016-04-08  Maxim Ostapenko  <m.ostapenko@samsung.com>

	PR sanitizer/70541
	* c-c++-common/asan/pr70541.c: New test.

diff --git a/gcc/asan.c b/gcc/asan.c
index 47bfdcd..71095fb 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -1766,6 +1766,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
 
   tree type, base;
   HOST_WIDE_INT size_in_bytes;
+  if (location == UNKNOWN_LOCATION)
+    location = EXPR_LOCATION (t);
 
   type = TREE_TYPE (t);
   switch (TREE_CODE (t))
@@ -2049,6 +2051,7 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
       gsi_insert_before (iter, g, GSI_SAME_STMT);
     }
 
+  bool instrumented = false;
   if (gimple_store_p (stmt))
     {
       tree ref_expr = gimple_call_lhs (stmt);
@@ -2056,11 +2059,30 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
 			 gimple_location (stmt),
 			 /*is_store=*/true);
 
-      gsi_next (iter);
-      return true;
+      instrumented = true;
     }
 
-  return false;
+  /* Walk through gimple_call arguments and check them id needed.  */
+  unsigned args_num = gimple_call_num_args (stmt);
+  for (unsigned i = 0; i < args_num; ++i)
+    {
+      tree arg = gimple_call_arg (stmt, i);
+      /* If ARG is not a non-aggregate register variable, compiler in general
+	 creates temporary for it and pass it as argument to gimple call.
+	 But in some cases, e.g. when we pass by value a small structure that
+	 fits to register, compiler can avoid extra overhead by pulling out
+	 these temporaries.  In this case, we should check the argument.  */
+      if (!is_gimple_reg (arg) && !is_gimple_min_invariant (arg))
+	{
+	  instrument_derefs (iter, arg,
+			     gimple_location (stmt),
+			     /*is_store=*/false);
+	  instrumented = true;
+	}
+    }
+  if (instrumented)
+    gsi_next (iter);
+  return instrumented;
 }
 
 /* Walk each instruction of all basic block and instrument those that
diff --git a/gcc/testsuite/c-c++-common/asan/pr70541.c b/gcc/testsuite/c-c++-common/asan/pr70541.c
new file mode 100644
index 0000000..b2a4bd5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pr70541.c
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct Simple {
+  int value;
+};
+
+int f(struct Simple simple) {
+  return simple.value;
+}
+
+int main() {
+  struct Simple *psimple = (struct Simple *) malloc(sizeof(struct Simple));
+  psimple->value = 42;
+  free(psimple);
+  printf("%d\n", f(*psimple));
+  return 0;
+}
+
+/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
+/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*pr70541.c:21|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*pr70541.c:20|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*pr70541.c:18|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */

      reply	other threads:[~2016-04-08 10:51 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-08  8:52 Maxim Ostapenko
2016-04-08  9:12 ` Jakub Jelinek
2016-04-08 10:51   ` Maxim Ostapenko [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=57078D0B.5050703@samsung.com \
    --to=m.ostapenko@samsung.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=hubicka@ucw.cz \
    --cc=jakub@redhat.com \
    --cc=rguenther@suse.de \
    --cc=v.garbuzov@samsung.com \
    --cc=y.gribov@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).