Bug 307828

Summary: SSE optimized wcscpy, wcscmp, wcsrchr and wcschr trigger uninitialised value and/or invalid read warnings
Product: [Developer tools] valgrind Reporter: Mark Wielaard <mark>
Component: memcheckAssignee: Julian Seward <jseward>
Status: RESOLVED FIXED    
Severity: normal CC: david.dyck, ishikawa
Priority: NOR    
Version: 3.9.0.SVN   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Attachments: Patch that implements overrides in mc_replace_strmem.c plus example code as test case

Description Mark Wielaard 2012-10-04 11:47:56 UTC
Take the following example code:

// Uses various wchar_t * functions that have hand written SSE assembly
// implementations in glibc. wcslen, wcscpy, wcscmp, wcsrchr, wcschr.

#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>

int main(int argc, char **argv)
{
  wchar_t a[] = L"The spazzy orange tiger jumped over the tawny jaguar.";
  wchar_t *b, *c;
  wchar_t *d, *e;

  size_t l = wcslen (a);
  fprintf (stderr, "wcslen: %zd\n", l); // wcslen: 53

  b = (wchar_t *) malloc((l + 1) * sizeof (wchar_t));
  c = wcscpy (b, a);

  fprintf (stderr, "wcscmp equal: %d\n", wcscmp (a, b)); // wcscmp equal: 0

  d = wcsrchr (a, L'd');
  e = wcschr (a, L'd');

  fprintf (stderr, "wcsrchr == wcschr: %d\n", d == e); // wcsrchr == wcschr: 1

  free (c); // b == c
  return 0;
}

On Fedora 17, x86_64 this triggers:
wcslen: 53
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4F88914: __wcscpy_ssse3 (wcscpy-ssse3.S:156)
==9250==    by 0x4007AB: main (wcs.c:18)
==9250== 
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4F8897E: __wcscpy_ssse3 (wcscpy-ssse3.S:191)
==9250==    by 0x4007AB: main (wcs.c:18)
==9250== 
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4F88D68: __wcscpy_ssse3 (wcscpy-ssse3.S:499)
==9250==    by 0x4007AB: main (wcs.c:18)
==9250== 
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4F88D6C: __wcscpy_ssse3 (wcscpy-ssse3.S:501)
==9250==    by 0x4007AB: main (wcs.c:18)
==9250== 
==9250== Invalid read of size 8
==9250==    at 0x4ECD799: wcscmp (wcscmp.S:435)
==9250==    by 0x4007C5: main (wcs.c:20)
==9250==  Address 0x51e6118 is 0 bytes after a block of size 216 alloc'd
==9250==    at 0x4C286FC: malloc (vg_replace_malloc.c:270)
==9250==    by 0x400791: main (wcs.c:17)
==9250== 
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4ECD7AC: wcscmp (wcscmp.S:439)
==9250==    by 0x4007C5: main (wcs.c:20)
==9250== 
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4ECDD74: wcscmp (wcscmp.S:834)
==9250==    by 0x4007C5: main (wcs.c:20)
==9250== 
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4ECDD79: wcscmp (wcscmp.S:836)
==9250==    by 0x4007C5: main (wcs.c:20)
==9250== 
wcscmp equal: 0
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4ECE678: wcsrchr (wcsrchr.S:112)
==9250==    by 0x4007F4: main (wcs.c:22)
==9250== 
==9250== Conditional jump or move depends on uninitialised value(s)
==9250==    at 0x4ECE6C3: wcsrchr (wcsrchr.S:135)
==9250==    by 0x4007F4: main (wcs.c:22)
==9250== 
wcsrchr == wcschr: 1

And on Fedora 17, i686:
wcslen: 53
==9242== Conditional jump or move depends on uninitialised value(s)
==9242==    at 0x41B3F34: __wcscpy_ssse3 (in /usr/lib/libc-2.15.so)
==9242==    by 0x4076634: (below main) (in /usr/lib/libc-2.15.so)
==9242== 
==9242== Conditional jump or move depends on uninitialised value(s)
==9242==    at 0x41B3E8B: __wcscpy_ssse3 (in /usr/lib/libc-2.15.so)
==9242==    by 0x4076634: (below main) (in /usr/lib/libc-2.15.so)
==9242== 
==9242== Conditional jump or move depends on uninitialised value(s)
==9242==    at 0x41B3F77: __wcscpy_ssse3 (in /usr/lib/libc-2.15.so)
==9242==    by 0x4076634: (below main) (in /usr/lib/libc-2.15.so)
==9242== 
==9242== Conditional jump or move depends on uninitialised value(s)
==9242==    at 0x41B3F93: __wcscpy_ssse3 (in /usr/lib/libc-2.15.so)
==9242==    by 0x4076634: (below main) (in /usr/lib/libc-2.15.so)
==9242== 
wcscmp equal: 0
==9242== Conditional jump or move depends on uninitialised value(s)
==9242==    at 0x41B3804: __wcsrchr_sse2 (in /usr/lib/libc-2.15.so)
==9242==    by 0x4076634: (below main) (in /usr/lib/libc-2.15.so)
==9242== 
==9242== Conditional jump or move depends on uninitialised value(s)
==9242==    at 0x41B3842: __wcsrchr_sse2 (in /usr/lib/libc-2.15.so)
==9242==    by 0x4076634: (below main) (in /usr/lib/libc-2.15.so)
==9242== 
wcsrchr == wcschr: 1

This is an extended bug report from Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=755242
Comment 1 Mark Wielaard 2012-10-04 11:49:33 UTC
Created attachment 74332 [details]
Patch that implements overrides in mc_replace_strmem.c plus example code as test case
Comment 2 zephyrus00jp 2012-11-08 16:41:50 UTC
A similar problem happens with memcpy (a ka bcopy).

If I compile and run the program below and run it under valgrind, I got the following error shown below. It seems to access outside the allocated area (by malloc()).
Now, in the real world example, I think I saw a case where the memory AFTER allocated area is accessed.

I am not sure if this is the problem of gnu libc itself or the emulation of CPU hardware done in valgrind.

*IF* bcopy under linux (GNU libc that is) does access outside the
properly allocated (or mapped) area, this may indeed cause a problem
under certain circumstances. (If the copied area is near the end of area obtained by brk(), the access beyond that would cause segmentation error.)

I wonder if this is a real bug, but something that is an arti-fact caused by
valgrind.

TIA


--- begin quote ---
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

main()
{
#define SIZE (32 * 1024)
  char *sp;
  char *dp;
  int i;
  int j;
  int k;

  for (j = 246; j < 279; j++)
    {
      for (i = 0; i < 33; i ++ ) 
	{
	  for(k = 0; k < 24; k++)
	    {
	      printf("i, j, k = %d, %d, %d\n", i, j, k);
	      fflush(stdout);
	      sp = malloc(j + 64 + 8);
	      dp = malloc(j + 64 + 8);
	      bzero(&sp[i], j);
	      bcopy(&sp[i], &dp[k], j);
	      free(sp);
	      free(dp);
	    }

	}
    }
  
}
--- end quote




==6952== Memcheck, a memory error detector
==6952== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==6952== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==6952== Command: ./a.out
==6952== 
i, j, k = 0, 246, 0
i, j, k = 0, 246, 1
==6952== Invalid read of size 8
==6952==    at 0x4166029: __bcopy_ssse3 (memcpy-ssse3.S:1026)
==6952==    by 0x4062E45: (below main) (libc-start.c:228)
==6952==  Address 0x41ab300 is 8 bytes before a block of size 318 alloc'd
==6952==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==6952==    by 0x80485AC: main (test-copy.c:22)
==6952== 
i, j, k = 0, 246, 2
==6952== Invalid read of size 8
==6952==    at 0x4165F99: __bcopy_ssse3 (memcpy-ssse3.S:981)
==6952==    by 0x4062E45: (below main) (libc-start.c:228)
==6952==  Address 0x41ab5e0 is 8 bytes before a block of size 318 alloc'd
==6952==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==6952==    by 0x80485AC: main (test-copy.c:22)
==6952== 
i, j, k = 0, 246, 3
==6952== Invalid read of size 8
==6952==    at 0x4165F09: __bcopy_ssse3 (memcpy-ssse3.S:936)
==6952==    by 0x4062E45: (below main) (libc-start.c:228)
==6952==  Address 0x41ab8c0 is 8 bytes before a block of size 318 alloc'd
==6952==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==6952==    by 0x80485AC: main (test-copy.c:22)
==6952== 
i, j, k = 0, 246, 4
==6952== Invalid read of size 8
==6952==    at 0x4165E79: __bcopy_ssse3 (memcpy-ssse3.S:891)
==6952==    by 0x4062E45: (below main) (libc-start.c:228)
==6952==  Address 0x41abba0 is 8 bytes before a block of size 318 alloc'd
==6952==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==6952==    by 0x80485AC: main (test-copy.c:22)
==6952== 
i, j, k = 0, 246, 5
==6952== Invalid read of size 8
==6952==    at 0x4165DE9: __bcopy_ssse3 (memcpy-ssse3.S:846)
==6952==    by 0x4062E45: (below main) (libc-start.c:228)
==6952==  Address 0x41abe80 is 8 bytes before a block of size 318 alloc'd
==6952==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==6952==    by 0x80485AC: main (test-copy.c:22)
==6952== 
i, j, k = 0, 246, 6
==6952== Invalid read of size 8
==6952==    at 0x4165D59: __bcopy_ssse3 (memcpy-ssse3.S:801)
==6952==    by 0x4062E45: (below main) (libc-start.c:228)
==6952==  Address 0x41ac160 is 8 bytes before a block of size 318 alloc'd
==6952==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==6952==    by 0x80485AC: main (test-copy.c:22)
==6952== 
i, j, k = 0, 246, 7
==6952== Invalid read of size 8
==6952==    at 0x4165CC9: __bcopy_ssse3 (memcpy-ssse3.S:756)
==6952==    by 0x4062E45: (below main) (libc-start.c:228)
==6952==  Address 0x41ac440 is 8 bytes before a block of size 318 alloc'd
==6952==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==6952==    by 0x80485AC: main (test-copy.c:22)
==6952== 
i, j, k = 0, 246, 8
   ...
i, j, k = 32, 278, 23
==6952== 
==6952== HEAP SUMMARY:
==6952==     in use at exit: 0 bytes in 0 blocks
==6952==   total heap usage: 52,272 allocs, 52,272 frees, 17,458,848 bytes allocated
==6952== 
==6952== All heap blocks were freed -- no leaks are possible
==6952== 
==6952== For counts of detected and suppressed errors, rerun with: -v
==6952== ERROR SUMMARY: 1176 errors from 7 contexts (suppressed: 11 from 6)
Comment 3 Julian Seward 2012-12-06 17:16:47 UTC
(In reply to comment #1)
> Patch that implements overrides in mc_replace_strmem.c plus example code as
> test case

Committed, r13162.  Thanks.
Comment 4 Julian Seward 2012-12-06 17:20:25 UTC
(In reply to comment #2)
> A similar problem happens with memcpy (a ka bcopy).

I can't reproduce this on Ubuntu 10.04.4 LTS (x86_64).  If you can
still reproduce it, please open a new bug report add enough details
so we can reproduce the problem.  (distro, version, gcc version,
glibc version)
Comment 5 zephyrus00jp 2012-12-09 13:15:39 UTC
(In reply to comment #4)
> (In reply to comment #2)
> > A similar problem happens with memcpy (a ka bcopy).
> 
> I can't reproduce this on Ubuntu 10.04.4 LTS (x86_64).  If you can
> still reproduce it, please open a new bug report add enough details
> so we can reproduce the problem.  (distro, version, gcc version,
> glibc version)

I am still seeing this on my PC.
So I filed a new bug report,
Bug 311407 - ssse3 bcopy (actually converted memcpy) causes invalid read of size 8 under Debian GNU/Linux 32 bits

TIA
Comment 6 Philippe Waroquiers 2013-11-02 16:44:15 UTC
*** Bug 326955 has been marked as a duplicate of this bug. ***