Bug 311407

Summary: ssse3 bcopy (actually converted memcpy) causes invalid read of size 8 under Debian GNU/Linux 32 bits
Product: [Developer tools] valgrind Reporter: zephyrus00jp <ishikawa>
Component: memcheckAssignee: Julian Seward <jseward>
Status: RESOLVED FIXED    
Severity: normal CC: nth10sd, tom
Priority: NOR    
Version: 3.8.0   
Target Milestone: ---   
Platform: Debian testing   
OS: Linux   
Latest Commit: Version Fixed In:

Description zephyrus00jp 2012-12-09 13:14:48 UTC
(Advised to file a separate bug : the original is in
https://bugs.kde.org/show_bug.cgi?id=307828#c2     )

f 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()). 

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

Distro: Debian GNU/Linux 32 bits (using testing repository)
 uname -a
Linux debian-vm 3.2.0-4-686-pae #1 SMP Debian 3.2.32-1 i686 GNU/Linux

GCC version:
 gcc --version
gcc (Debian 4.7.1-7) 4.7.1
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

libc version: 2.13.1

(memcpy-bug is the name of the program I compiled from the source below.)
ldd memcpy-bug
	linux-gate.so.1 =>  (0xb778b000)
	libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb760e000)
	/lib/ld-linux.so.2 (0xb778c000)

ls -l /lib/i386-linux-gnu/i686/cmov/{libc.*,libc-*.*}
-rwxr-xr-x 1 root root 1413288  7月 23 06:44 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so*
lrwxrwxrwx 1 root root      12  7月 23 06:44 /lib/i386-linux-gnu/i686/cmov/libc.so.6 -> libc-2.13.so*

I searched for a version string in libc-2.13.so and found the following.
GNU C Library (Debian EGLIBC 2.13-35) stable release version 2.13, by Roland McGrath et al.

valgrind: 3.8.1   (I compiled this myself from source.)
valgrind --version
valgrind-3.8.1

Reproducible: Always

Steps to Reproduce:
1. Compile the following program.
2. Run it under valgrind, and see the messages.
3. The file memcpy-bug.c is here.

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

#define SIZE (32 * 1024) 

main() 
{ 
	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); 
			} 
		} 
	} 
	exit(EXIT_SUCCESS);
}

Actual Results:  
Excerpt from the messages produced from valgrind.

$ valgrind ./memcpy-bug
==1564== Memcheck, a memory error detector
==1564== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==1564== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==1564== Command: ./memcpy-bug
==1564== 
i, j, k = 0, 246, 0
i, j, k = 0, 246, 1
==1564== Invalid read of size 8
==1564==    at 0x4166029: __bcopy_ssse3 (memcpy-ssse3.S:1026)
==1564==    by 0x4062E45: (below main) (libc-start.c:228)
==1564==  Address 0x41ab300 is 8 bytes before a block of size 318 alloc'd
==1564==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==1564==    by 0x80485EC: main (in /TB-NEW/TB-3HG/work-dir/memcpy-bug)
==1564== 
i, j, k = 0, 246, 2
==1564== Invalid read of size 8
==1564==    at 0x4165F99: __bcopy_ssse3 (memcpy-ssse3.S:981)
==1564==    by 0x4062E45: (below main) (libc-start.c:228)
==1564==  Address 0x41ab5e0 is 8 bytes before a block of size 318 alloc'd
==1564==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==1564==    by 0x80485EC: main (in /TB-NEW/TB-3HG/work-dir/memcpy-bug)
==1564== 
i, j, k = 0, 246, 3
==1564== Invalid read of size 8
==1564==    at 0x4165F09: __bcopy_ssse3 (memcpy-ssse3.S:936)
==1564==    by 0x4062E45: (below main) (libc-start.c:228)
==1564==  Address 0x41ab8c0 is 8 bytes before a block of size 318 alloc'd
==1564==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==1564==    by 0x80485EC: main (in /TB-NEW/TB-3HG/work-dir/memcpy-bug)
==1564== 
i, j, k = 0, 246, 4
==1564== Invalid read of size 8
==1564==    at 0x4165E79: __bcopy_ssse3 (memcpy-ssse3.S:891)
==1564==    by 0x4062E45: (below main) (libc-start.c:228)
==1564==  Address 0x41abba0 is 8 bytes before a block of size 318 alloc'd
==1564==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==1564==    by 0x80485EC: main (in /TB-NEW/TB-3HG/work-dir/memcpy-bug)
==1564== 
i, j, k = 0, 246, 5
==1564== Invalid read of size 8
==1564==    at 0x4165DE9: __bcopy_ssse3 (memcpy-ssse3.S:846)
==1564==    by 0x4062E45: (below main) (libc-start.c:228)
==1564==  Address 0x41abe80 is 8 bytes before a block of size 318 alloc'd
==1564==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==1564==    by 0x80485EC: main (in /TB-NEW/TB-3HG/work-dir/memcpy-bug)
==1564== 
i, j, k = 0, 246, 6
==1564== Invalid read of size 8
==1564==    at 0x4165D59: __bcopy_ssse3 (memcpy-ssse3.S:801)
==1564==    by 0x4062E45: (below main) (libc-start.c:228)
==1564==  Address 0x41ac160 is 8 bytes before a block of size 318 alloc'd
==1564==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==1564==    by 0x80485EC: main (in /TB-NEW/TB-3HG/work-dir/memcpy-bug)
==1564== 
i, j, k = 0, 246, 7
==1564== Invalid read of size 8
==1564==    at 0x4165CC9: __bcopy_ssse3 (memcpy-ssse3.S:756)
==1564==    by 0x4062E45: (below main) (libc-start.c:228)
==1564==  Address 0x41ac440 is 8 bytes before a block of size 318 alloc'd
==1564==    at 0x40271C4: malloc (vg_replace_malloc.c:270)
==1564==    by 0x80485EC: main (in /TB-NEW/TB-3HG/work-dir/memcpy-bug)
==1564== 
i, j, k = 0, 246, 8
i, j, k = 0, 246, 9
i, j, k = 0, 246, 10
i, j, k = 0, 246, 11
i, j, k = 0, 246, 12
i, j, k = 0, 246, 13
i, j, k = 0, 246, 14
i, j, k = 0, 246, 15
i, j, k = 0, 246, 16
i, j, k = 0, 246, 17
i, j, k = 0, 246, 18
i, j, k = 0, 246, 19
i, j, k = 0, 246, 20
i, j, k = 0, 246, 21
i, j, k = 0, 246, 22
i, j, k = 0, 246, 23
i, j, k = 1, 246, 0
i, j, k = 1, 246, 1
i, j, k = 1, 246, 2
i, j, k = 1, 246, 3
  ...
i, j, k = 31, 278, 19
i, j, k = 31, 278, 20
i, j, k = 31, 278, 21
i, j, k = 31, 278, 22
i, j, k = 31, 278, 23
i, j, k = 32, 278, 0
i, j, k = 32, 278, 1
i, j, k = 32, 278, 2
i, j, k = 32, 278, 3
i, j, k = 32, 278, 4
i, j, k = 32, 278, 5
i, j, k = 32, 278, 6
i, j, k = 32, 278, 7
i, j, k = 32, 278, 8
i, j, k = 32, 278, 9
i, j, k = 32, 278, 10
i, j, k = 32, 278, 11
i, j, k = 32, 278, 12
i, j, k = 32, 278, 13
i, j, k = 32, 278, 14
i, j, k = 32, 278, 15
i, j, k = 32, 278, 16
i, j, k = 32, 278, 17
i, j, k = 32, 278, 18
i, j, k = 32, 278, 19
i, j, k = 32, 278, 20
i, j, k = 32, 278, 21
i, j, k = 32, 278, 22
i, j, k = 32, 278, 23
==1564== 
==1564== HEAP SUMMARY:
==1564==     in use at exit: 0 bytes in 0 blocks
==1564==   total heap usage: 52,272 allocs, 52,272 frees, 17,458,848 bytes allocated
==1564== 
==1564== All heap blocks were freed -- no leaks are possible
==1564== 
==1564== For counts of detected and suppressed errors, rerun with: -v
==1564== ERROR SUMMARY: 1176 errors from 7 contexts (suppressed: 11 from 6)
 

Expected Results:  
I should not see the warning.

Not sure again whether this is valgrind replacement library for memcpy(?) or
glibc ?



Now, in the real world example where I noticed the problem and
created the  example program quoted here after I distilled the essence,
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.)
Comment 1 zephyrus00jp 2013-01-21 02:36:34 UTC
Hi,

This issue is observed in a real-world example of trying to debug 
memory-related issues of mozilla thunderbird mail client.

As far as the program was concerned, these warnings are generated that a certain length of memory copy (length=31 is a clear indication) [and particular
memory layout] seems to trigger this warning.
Since there have been these false positives (noted above) [or maybe the
substituded memcpy during valgrind run DOES HAVE  the memory issue.],
it is quite annoying to see many of these warnings somehow.

I am trying to see if there is a similar bug report in Debian ( or anywhere else. I notice similar ones date a couple of years ago or older [some of them were reported to be fixed.], but not recent one.)

Any pointers on this issue will be appreciated.

Excerpt from a session log: (the line numbers may be off from the pristine copy
of TB (comm-central) version due to local modification.
(Recorded during debugging the issue reported in
https://bugzilla.mozilla.org/show_bug.cgi?id=814870
Bug 814870 - Invalid read of size 1 in PR_ParseTimeStringToExplodedTime (prtime.c:1450))


date->length=31

==24420== Invalid read of size 8

==24420==    at 0x42B719F: __bcopy_ssse3 (memcpy-ssse3.S:720)

==24420==    by 0xA67585C: nsParseMailMessageState::ParseFolderLine(char const*, unsigned int) (nsParseMailbox.cpp:714)

==24420==    by 0xA6699A0: nsMsgMailboxParser::HandleLine(char*, unsigned int) (nsParseMailbox.cpp:518)

==24420==    by 0xA4D52F0: nsMsgLineBuffer::ConvertAndSendBuffer() (nsMsgLineBuffer.cpp:233)
  ...
Comment 2 Julian Seward 2013-01-21 11:23:16 UTC
(In reply to comment #0)
> If I compile and run the program below and run it under valgrind, I got the
> following error shown below. 

I can't reproduce this, using your test program, Valgrind SVN trunk,
"gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)" on Fedora 17.  Can you
reproduce it using the Valgrind SVN trunk?
Comment 3 zephyrus00jp 2013-01-21 12:27:43 UTC
(2013/01/21 20:23), Julian Seward wrote:
> https://bugs.kde.org/show_bug.cgi?id=311407
>
> --- Comment #2 from Julian Seward <jseward@acm.org> ---
> (In reply to comment #0)
>> If I compile and run the program below and run it under valgrind, I got the
>> following error shown below.
>
> I can't reproduce this, using your test program, Valgrind SVN trunk,
> "gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)" on Fedora 17.  Can you
> reproduce it using the Valgrind SVN trunk?
>

Dear Julian,

Thank you for your message.

OK, I will check the operation using SVN version.

Best Regards,
Chiaki
Comment 4 zephyrus00jp 2013-01-21 14:51:53 UTC
This is again observed with valgrind SVN version under 32-bit version of Debian GNU/linux.

System info is
$ uname -a
Linux debian-vm 3.2.0-4-686-pae #1 SMP Debian 3.2.32-1 i686 GNU/Linux
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i486-linux-gnu/4.7/lto-wrapper
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.2-4' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.7.2 (Debian 4.7.2-4) 
$ 

/tmp/a.out is the compiled version of the sample program.

ishikawa@debian-vm:/tmp$ valgrind /tmp/a.out
==32715== Memcheck, a memory error detector
==32715== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==32715== Using Valgrind-3.9.0.SVN and LibVEX; rerun with -h for copyright info
==32715== Command: /tmp/a.out
==32715== 
i, j, k = 0, 246, 0
i, j, k = 0, 246, 1
==32715== Invalid read of size 8
==32715==    at 0x416D579: __bcopy_ssse3 (memcpy-ssse3.S:1026)
==32715==    by 0x4064E45: (below main) (libc-start.c:228)
==32715==  Address 0x41b3300 is 8 bytes before a block of size 318 alloc'd
==32715==    at 0x4027388: malloc (vg_replace_malloc.c:270)
==32715==    by 0x80485EC: main (test-copy-2.c:22)
==32715== 
i, j, k = 0, 246, 2
==32715== Invalid read of size 8
==32715==    at 0x416D4E9: __bcopy_ssse3 (memcpy-ssse3.S:981)
==32715==    by 0x4064E45: (below main) (libc-start.c:228)
==32715==  Address 0x41b35e0 is 8 bytes before a block of size 318 alloc'd
==32715==    at 0x4027388: malloc (vg_replace_malloc.c:270)
==32715==    by 0x80485EC: main (test-copy-2.c:22)
==32715== 
i, j, k = 0, 246, 3
==32715== Invalid read of size 8
==32715==    at 0x416D459: __bcopy_ssse3 (memcpy-ssse3.S:936)
==32715==    by 0x4064E45: (below main) (libc-start.c:228)
==32715==  Address 0x41b38c0 is 8 bytes before a block of size 318 alloc'd
==32715==    at 0x4027388: malloc (vg_replace_malloc.c:270)
==32715==    by 0x80485EC: main (test-copy-2.c:22)
==32715== 
i, j, k = 0, 246, 4
==32715== Invalid read of size 8
==32715==    at 0x416D3C9: __bcopy_ssse3 (memcpy-ssse3.S:891)
==32715==    by 0x4064E45: (below main) (libc-start.c:228)
==32715==  Address 0x41b3ba0 is 8 bytes before a block of size 318 alloc'd
==32715==    at 0x4027388: malloc (vg_replace_malloc.c:270)
==32715==    by 0x80485EC: main (test-copy-2.c:22)
==32715== 
i, j, k = 0, 246, 5
==32715== Invalid read of size 8
==32715==    at 0x416D339: __bcopy_ssse3 (memcpy-ssse3.S:846)
==32715==    by 0x4064E45: (below main) (libc-start.c:228)
==32715==  Address 0x41b3e80 is 8 bytes before a block of size 318 alloc'd
==32715==    at 0x4027388: malloc (vg_replace_malloc.c:270)
==32715==    by 0x80485EC: main (test-copy-2.c:22)
==32715== 
i, j, k = 0, 246, 6
==32715== Invalid read of size 8
==32715==    at 0x416D2A9: __bcopy_ssse3 (memcpy-ssse3.S:801)
==32715==    by 0x4064E45: (below main) (libc-start.c:228)
==32715==  Address 0x41b4160 is 8 bytes before a block of size 318 alloc'd
==32715==    at 0x4027388: malloc (vg_replace_malloc.c:270)
==32715==    by 0x80485EC: main (test-copy-2.c:22)
==32715== 
i, j, k = 0, 246, 7
==32715== Invalid read of size 8
==32715==    at 0x416D219: __bcopy_ssse3 (memcpy-ssse3.S:756)
==32715==    by 0x4064E45: (below main) (libc-start.c:228)
==32715==  Address 0x41b4440 is 8 bytes before a block of size 318 alloc'd
==32715==    at 0x4027388: malloc (vg_replace_malloc.c:270)
==32715==    by 0x80485EC: main (test-copy-2.c:22)
==32715== 
i, j, k = 0, 246, 8
i, j, k = 0, 246, 9
i, j, k = 0, 246, 10
i, j, k = 0, 246, 11
i, j, k = 0, 246, 12
i, j, k = 0, 246, 13
i, j, k = 0, 246, 14
 ...
i, j, k = 32, 278, 22
i, j, k = 32, 278, 23
==32715== 
==32715== HEAP SUMMARY:
==32715==     in use at exit: 0 bytes in 0 blocks
==32715==   total heap usage: 52,272 allocs, 52,272 frees, 17,458,848 bytes allocated
==32715== 
==32715== All heap blocks were freed -- no leaks are possible
==32715== 
==32715== For counts of detected and suppressed errors, rerun with: -v
==32715== ERROR SUMMARY: 1176 errors from 7 contexts (suppressed: 11 from 6)

I have no idea, but only differences of your environment and mine I can think of
are 
 - I am using 32 bits version of Debian GNU/Linux, and
 - Debian seems to use a so called embedded libc (derived from GNU libc).

I wonder if the memcpy.-ssse3S is from valgrind/memcheck or Debian's libc.
Debian 32bit libc  may not contain a proper fix for the type of problems earlier reported in
https://bugzilla.redhat.com/show_bug.cgi?id=705790

I also found a reference about overeager reading of some library routines in
http://code.google.com/p/chromium/issues/detail?id=58730

I don't think just hiding this under the rug using suppression as suggested
in the above article is good because
such eager reading CAN end in an invalid memory access and segfault if the program is looking at the upper end of the user area allocated by sbrk()/brk()(unless the library checks for this condition by comparing sbrk() value and takes proper precaution not to overstep.)

I wonder which version of memcopy-ssse3.S is used after all.

TIA
Comment 5 Tom Hughes 2013-01-21 15:11:57 UTC
I can reproduce this when compiled for 32 bits on Fedora, but not when compiled for 64 bits.
Comment 6 Tom Hughes 2013-01-21 15:17:22 UTC
Fix committed as r13253.
Comment 7 zephyrus00jp 2013-01-21 16:00:27 UTC
(In reply to comment #6)
> Fix committed as r13253.

Thank you! I pulled the SVN source tree and I no longer see the problem.
Comment 8 zephyrus00jp 2013-01-21 17:00:09 UTC
Well, the patch seemed to fix the particular problem noticed by the
test program posted here.

Is there any chance that the patch missed off-by-one error?

I now get the following error message from memcheck during of debugging
of TB and not quite sure if I should believe the message to be correct or not :-(
[At least now I notice that bcopy is replaced with a mc_replace_strmem.c version.]

date->length=31
==2958== Invalid read of size 1
==2958==    at 0x402A450: bcopy (mc_replace_strmem.c:1106)
==2958==    by 0xA67469B: nsParseMailMessageState::FinalizeHeaders() (nsParseMailbox.cpp:1674)

	    [...]

==2958==    by 0xB62B76E: js::CallJSNative(JSContext*, int (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) (jscntxtinlines.h:373)
==2958==  Address 0x700483f is 1 bytes before a block of size 204 alloc'd
==2958==    at 0x40273B8: malloc (vg_replace_malloc.c:270)
==2958==    by 0x404BE13: moz_xmalloc (mozalloc.cpp:54)
==2958==    by 0xADF42C3: NS_Alloc_P (nsMemoryImpl.cpp:198)

So maybe the bug of invalid read of one byte is for real, but I just wanted to
be sure since the fix is very new and maybe I thought there can be
a subtle bug in valgrind memcpy version.

TIA
Comment 9 zephyrus00jp 2013-01-21 17:20:03 UTC
Sorry, I think the previous waring is for real.
There was a bug in my data dumping code that seems to refer to the uninitialized data area. Sorry for the noise.

TIA