Bug 162129

Summary: *** glibc detected *** free(): invalid next size (fast): 0x0000000000502150 *** Aborted
Product: Red Hat Enterprise Linux 4 Reporter: sangameshwar Allipuram <asangameshwar>
Component: glibcAssignee: Jakub Jelinek <jakub>
Status: CLOSED NOTABUG QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 4.0   
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2005-06-30 07:54:34 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description sangameshwar Allipuram 2005-06-30 06:39:29 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4.2) Gecko/20040301

Description of problem:
The sample program written in C++ fails with this following error.

*** glibc detected *** free(): invalid next size (fast): 0x0000000000502150 ***

I am using x86_64 opteron machine with RHEL 4.0. I debugged with gdb in which
which i found there is no problem in the program code which i am providing down.

This bug is occurring at line pointed "->" in the program below. When i replaced
all the lines in this sample program pointing with ">", with c style "malloc" and string functions, this program works fine. And also works fine when i set
MALLOC_CHECK_=0.

I am providing the part of gdb output with back trace in the additional information section.

Thanks alot in advance for help.

-------------------------------- replicate.cc ----------------------------
#include <iostream>
#include <string>
                                                                                                                                               
using namespace std;
                                                                                                                                               
int main(int argc, char *argv[])
{
std::string c_line("ppp -L/home/sangam/xxx/XXXX/lib -D__DDDD -D__XXXXXXX a.c -I/home/sangam/xxx/XXXX/include -L/home/sangam/xxx/XXXX/lib/xxxx -lxxXxxx -lXXxxxxxxXX ");
    int count_blanks = 9;
    int pos1,pos2;
    int i = 0;
    char **args;
  > std::string this_opt;
    args = new char *[count_blanks];
    pos1 = c_line.find_first_of(' ', 0);
    for (int i = 0; i < count_blanks - 1; i ++) {
        std::string::size_type pos2 = c_line.find_first_of(' ', pos1 + 1);
 ->     this_opt = c_line.substr(pos1 + 1, pos2 - (pos1 + 1));
  >     this_opt[pos2 - pos1] = '\0';
  >     args[i] = new char [this_opt.size() + 1];
  >     strcpy(args[i], this_opt.c_str());
        pos1 = pos2;
    }
    args[count_blanks - 1] = 0;
                                                                                                                                               
    while (args[i] != NULL)
    cout <<args[i++]<<endl;
}

-------------------------- End of replicate.cc ------------------------------

Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
$g++ replicate.cc -g -o replicate
$ ./replicate
*** glibc detected *** free(): invalid next size (fast): 0x0000000000502150 ***
Aborted

  

Actual Results:  *** glibc detected *** free(): invalid next size (fast): 0x0000000000502150 ***
Aborted

Expected Results:  $./replicate
$-L/home/sangam/xxx/XXXX/lib
-D__DDDD
-D__XXXXXXX
a.c
-I/home/sangam/xxx/XXXX/include
-L/home/sangam/xxx/XXXX/lib/xxxx
-lxxXxxx
-lXXxxxxxxXX

Additional info:

Part of gdb output with back trace.
------------------------------------

(gdb)
17              std::string::size_type pos2 = c_line.find_first_of(' ', pos1 + 1);
(gdb)
18              this_opt = c_line.substr(pos1 + 1, pos2 - (pos1 + 1));
(gdb)
19              this_opt[pos2 - pos1] = '\0';
(gdb)
20              args[i] = new char [this_opt.size() + 1];
(gdb)
21              strcpy(args[i], this_opt.c_str());
(gdb)
22              pos1 = pos2;
(gdb)
16          for (int i = 0; i < count_blanks - 1; i ++) {
(gdb)
17              std::string::size_type pos2 = c_line.find_first_of(' ', pos1 + 1);
(gdb)
18              this_opt = c_line.substr(pos1 + 1, pos2 - (pos1 + 1));
(gdb)
*** glibc detected *** free(): invalid next size (fast): 0x0000000000502150 ***
 
Program received signal SIGABRT, Aborted.
0x000000366762e37d in raise () from /lib64/tls/libc.so.6
(gdb) bt
#0  0x000000366762e37d in raise () from /lib64/tls/libc.so.6
#1  0x000000366762faae in abort () from /lib64/tls/libc.so.6
#2  0x0000003667662a01 in __libc_message () from /lib64/tls/libc.so.6
#3  0x00000036676685ce in _int_free () from /lib64/tls/libc.so.6
#4  0x0000003667668916 in free () from /lib64/tls/libc.so.6
#5  0x000000366a3adfde in operator delete () from /usr/lib64/libstdc++.so.6
#6  0x000000366a3903a2 in std::string::_Rep::_M_destroy () from /usr/lib64/libstdc++.so.6
#7  0x000000366a3904d5 in std::string::assign () from /usr/lib64/libstdc++.so.6
#8  0x000000366a390509 in std::string::operator= () from /usr/lib64/libstdc++.so.6
#9  0x0000000000400f2b in main (argc=1, argv=0x7fbffff958) at replecate.cc:18

Comment 1 Jakub Jelinek 2005-06-30 07:54:34 UTC
glibc just points a bug in your testcase.
If you used a memory allocation debugger like valgrind or ElectricFence, you'd
see it yourself clearly:
valgrind --tool=memcheck ./a
==31256== Memcheck, a memory error detector for x86-linux.
==31256== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.
==31256== Using valgrind-2.2.0, a program supervision framework for x86-linux.
==31256== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.
==31256== For more details, rerun with: -v
==31256==
==31256== Invalid write of size 1
==31256==    at 0x8048C5C: main (a.C:19)
==31256==  Address 0x1BB4B1C8 is 0 bytes after a block of size 40 alloc'd
==31256==    at 0x1B904AFB: operator new(unsigned) (vg_replace_malloc.c:133)
==31256==    by 0x1B9A5181: std::string::_Rep::_S_create(unsigned, unsigned,
std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.3)
==31256==    by 0x1B9A7296: (within /usr/lib/libstdc++.so.6.0.3)
==31256==    by 0x1B9A749A: std::string::string(std::string const&, unsigned,
unsigned) (in /usr/lib/libstdc++.so.6.0.3)
-L/home/sangam/xxx/XXXX/lib
-D__DDDD
-D__XXXXXXX
a.c
-I/home/sangam/xxx/XXXX/include
-L/home/sangam/xxx/XXXX/lib/xxxx
-lxxXxxx
-lXXxxxxxxXX
==31256==
==31256== ERROR SUMMARY: 8 errors from 1 contexts (suppressed: 19 from 1)
==31256== malloc/free: in use at exit: 176 bytes in 9 blocks.
==31256== malloc/free: 18 allocs, 9 frees, 652 bytes allocated.
==31256== For a detailed leak analysis,  rerun with: --leak-check=yes
==31256== For counts of detected errors, rerun with: -v

The bug is the
this_opt[pos2 - pos1] = '\0';
line.  a) it is unnecessary, it is STL's responsibility to make things terminated
b) is wrong.  You called substr with pos2 - pos1 - 1 length, which means the
string is pos2 - pos1 - 1 bytes long, at
this_opt[pos2 - pos1 - 1]
there is the terminating '\0'.  But by writing to this_opt[pos2 - pos1] you are
writing one past the terminating '\0', and there is absolutely no guarantee that
was allocated for the string.  It was not, so you are clobbering internal
malloc's control structures and glibc subsequently complains.

Comment 2 sangameshwar Allipuram 2005-06-30 09:00:38 UTC
Thanks alot for the help in solving the problem. I dont have valgrind tool.
Thanks again for help.

Comment 3 Jakub Jelinek 2005-06-30 09:45:26 UTC
valgrind-2.2.0-5.EL4 is shipped as part of RHEL4, though for the time being
it only supports 32-bit i?86 binaries/libraries, so you need to build with
-m32 if you want to use valgrind on your program.