diff mbox

gcc: fix segfault from calling free on non-malloc'd area

Message ID 1403534578-41451-1-git-send-email-paul.gortmaker@windriver.com
State New
Headers show

Commit Message

Paul Gortmaker June 23, 2014, 2:42 p.m. UTC
We see the following on a 32bit gcc installed on 64 bit host:

  Reading symbols from ./i586-pokymllib32-linux-gcc...done.
  (gdb) run
  Starting program: x86-pokymllib32-linux/lib32-gcc/4.9.0-r0/image/usr/bin/i586-pokymllib32-linux-gcc

  Program received signal SIGSEGV, Segmentation fault.
  0xf7e957e0 in free () from /lib/i386-linux-gnu/libc.so.6
  (gdb) bt
  #0  0xf7e957e0 in free () from /lib/i386-linux-gnu/libc.so.6
  #1  0x0804b73c in set_multilib_dir () at gcc-4.9.0/gcc/gcc.c:7827
  #2  main (argc=1, argv=0xffffd504) at gcc-4.9.0/gcc/gcc.c:6688
  (gdb)

The problem arises because the check on whether we are using
the internal string "." or an allocated one is reversed.
We should be calling free() when the string is not equal to
the internal "." string.

Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---

[Found and fixed on gcc-4.9.0 but applies to git/master too]

 gcc/gcc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Jeff Law June 23, 2014, 6:52 p.m. UTC | #1
On 06/23/14 08:42, Paul Gortmaker wrote:
> We see the following on a 32bit gcc installed on 64 bit host:
>
>    Reading symbols from ./i586-pokymllib32-linux-gcc...done.
>    (gdb) run
>    Starting program: x86-pokymllib32-linux/lib32-gcc/4.9.0-r0/image/usr/bin/i586-pokymllib32-linux-gcc
>
>    Program received signal SIGSEGV, Segmentation fault.
>    0xf7e957e0 in free () from /lib/i386-linux-gnu/libc.so.6
>    (gdb) bt
>    #0  0xf7e957e0 in free () from /lib/i386-linux-gnu/libc.so.6
>    #1  0x0804b73c in set_multilib_dir () at gcc-4.9.0/gcc/gcc.c:7827
>    #2  main (argc=1, argv=0xffffd504) at gcc-4.9.0/gcc/gcc.c:6688
>    (gdb)
>
> The problem arises because the check on whether we are using
> the internal string "." or an allocated one is reversed.
> We should be calling free() when the string is not equal to
> the internal "." string.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
>
> [Found and fixed on gcc-4.9.0 but applies to git/master too]
>
>   gcc/gcc.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index 6870a840e1b7..a580975a7057 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -7822,7 +7822,7 @@ set_multilib_dir (void)
>       }
>
>     if (multilib_dir == NULL && multilib_os_dir != NULL
> -      && strcmp (multilib_os_dir, ".") == 0)
> +      && strcmp (multilib_os_dir, ".") != 0)
>       {
>         free (CONST_CAST (char *, multilib_os_dir));
>         multilib_os_dir = NULL;
>
Thanks.  Installed on the trunk.
jeff
Tobias Burnus June 23, 2014, 8:09 p.m. UTC | #2
This patch broke bootstrapping for me on x86-64-gnu-linux:

/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld: 
i386 architecture of input file `/usr/lib/crti.o' is incompatible with 
i386:x86-64 output

If I revert the patch, it works for me.

Tobias

Paul Gortmaker wrote:
> We see the following on a 32bit gcc installed on 64 bit host:
>
>    Reading symbols from ./i586-pokymllib32-linux-gcc...done.
>    (gdb) run
>    Starting program: x86-pokymllib32-linux/lib32-gcc/4.9.0-r0/image/usr/bin/i586-pokymllib32-linux-gcc
>
>    Program received signal SIGSEGV, Segmentation fault.
>    0xf7e957e0 in free () from /lib/i386-linux-gnu/libc.so.6
>    (gdb) bt
>    #0  0xf7e957e0 in free () from /lib/i386-linux-gnu/libc.so.6
>    #1  0x0804b73c in set_multilib_dir () at gcc-4.9.0/gcc/gcc.c:7827
>    #2  main (argc=1, argv=0xffffd504) at gcc-4.9.0/gcc/gcc.c:6688
>    (gdb)
>
> The problem arises because the check on whether we are using
> the internal string "." or an allocated one is reversed.
> We should be calling free() when the string is not equal to
> the internal "." string.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
>
> [Found and fixed on gcc-4.9.0 but applies to git/master too]
>
>   gcc/gcc.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/gcc/gcc.c b/gcc/gcc.c
> index 6870a840e1b7..a580975a7057 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -7822,7 +7822,7 @@ set_multilib_dir (void)
>       }
>
>     if (multilib_dir == NULL && multilib_os_dir != NULL
> -      && strcmp (multilib_os_dir, ".") == 0)
> +      && strcmp (multilib_os_dir, ".") != 0)
>       {
>         free (CONST_CAST (char *, multilib_os_dir));
>         multilib_os_dir = NULL;
>
Jeff Law June 23, 2014, 8:32 p.m. UTC | #3
On 06/23/14 14:09, Tobias Burnus wrote:
> This patch broke bootstrapping for me on x86-64-gnu-linux:
>
> /usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld:
> i386 architecture of input file `/usr/lib/crti.o' is incompatible with
> i386:x86-64 output

>
> If I revert the patch, it works for me.
Reverted.  Will have to look deeper.  Paul, did you bootstrap with this 
patch on the trunk?

jeff
Jakub Jelinek June 23, 2014, 8:42 p.m. UTC | #4
On Mon, Jun 23, 2014 at 02:32:37PM -0600, Jeff Law wrote:
> On 06/23/14 14:09, Tobias Burnus wrote:
> >This patch broke bootstrapping for me on x86-64-gnu-linux:
> >
> >/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld:
> >i386 architecture of input file `/usr/lib/crti.o' is incompatible with
> >i386:x86-64 output
> 
> >
> >If I revert the patch, it works for me.
> Reverted.  Will have to look deeper.  Paul, did you bootstrap with this
> patch on the trunk?

I can see one spot where multilib_os_dir is set to non-malloced string
literal, and at that point we also leak memory.

So, supposedly:
              new_multilib_os_dir = XNEWVEC (char, ml_end - q);
              memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1);
              new_multilib_os_dir[ml_end - q - 1] = '\0';
              multilib_os_dir = *new_multilib_os_dir ? new_multilib_os_dir : ".";
should be instead:
	      if (ml_end - q == 1)
		multilib_os_dir = xstrdup (".");
	      else
		{
		  new_multilib_os_dir = XNEWVEC (char, ml_end - q);
		  memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1);
		  new_multilib_os_dir[ml_end - q - 1] = '\0';
		  multilib_os_dir = new_multilib_os_dir;
		}
or so (completely untested).  Bet this got broken when the multiarch support
has been added, before that multilib_os_dir has always been malloced.
Alternatively, multilib_os_dir could be set to NULL instead of setting it to
".".

	Jakub
Paul Gortmaker June 24, 2014, 3:40 a.m. UTC | #5
[Re: [PATCH] gcc: fix segfault from calling free on non-malloc'd area] On 23/06/2014 (Mon 14:32) Jeff Law wrote:

> On 06/23/14 14:09, Tobias Burnus wrote:
> >This patch broke bootstrapping for me on x86-64-gnu-linux:
> >
> >/usr/lib64/gcc/x86_64-suse-linux/4.8/../../../../x86_64-suse-linux/bin/ld:
> >i386 architecture of input file `/usr/lib/crti.o' is incompatible with
> >i386:x86-64 output
> 
> >
> >If I revert the patch, it works for me.
> Reverted.  Will have to look deeper.  Paul, did you bootstrap with
> this patch on the trunk?

Hi Jeff,

I was using the yocto/oe-core build system, and hence it was creating
gcc-cross-initial from its own build system (with ~50 other patches
on gcc-4.9.0 baseline)  -- so it isn't 100% identical to a manual
bootstrapping on trunk.

It sounds like Jakub has provided additional details on why this may
have broken bootstrap, as the issue appears to be possibly of wider
scope than I originally reported.  I'll revisit it tomorrow morning,
and see what additional details I can provide.

Thanks,
Paul.
--


> 
> jeff
> 
>
diff mbox

Patch

diff --git a/gcc/gcc.c b/gcc/gcc.c
index 6870a840e1b7..a580975a7057 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -7822,7 +7822,7 @@  set_multilib_dir (void)
     }
 
   if (multilib_dir == NULL && multilib_os_dir != NULL
-      && strcmp (multilib_os_dir, ".") == 0)
+      && strcmp (multilib_os_dir, ".") != 0)
     {
       free (CONST_CAST (char *, multilib_os_dir));
       multilib_os_dir = NULL;