c++ - Why do I need to initialize dynamically allocated array at allocation time with ()? -


i have following piece of code:

#include <cassert> #include <cstring> #include <iostream>  class line { public:   line(const char* c)   {     len = std::strlen(c);     text = new char[len + 1]();     std::strncpy(text, c, len);   }    line& operator=(const line& rhs)   {     if (&rhs == this) return *this;      delete[] text;     text = new char[rhs.getlen()]();     std::strncpy(text, rhs.gettext(), rhs.getlen());     return *this;   }    line(const line& rhs)   {     len = rhs.getlen();     text = new char[rhs.getlen() + 1]();     std::strncpy(text, rhs.gettext(), len);   }    ~line()   {     delete[] text;   }    unsigned getlen() const   {     return len;   }    char* gettext() const   {     return text;   }  private:   char* text;   unsigned len; };  // operator overloads  const line operator*(const line& lhs, const line& rhs) {   unsigned newlen = lhs.getlen() + rhs.getlen();   char* newc = new char[newlen + 1]();   std::strncat(newc, lhs.gettext(), lhs.getlen());   std::strncat(newc, rhs.gettext(), rhs.getlen());   line line(newc);   delete[] newc;   return line; }  bool operator==(const line& lhs, const line& rhs) {   return strcmp(lhs.gettext(), rhs.gettext()) == 0; }  std::ostream& operator<<(std::ostream& os, const line& l) {   os << l.gettext();   return os; }  int main(void) {   line l("hello");   line l2("hello");   line r("world");   line x = l * r;    assert(strcmp("hello", l.gettext()) == 0);   assert(strcmp("helloworld", x.gettext()) == 0);   assert(l == l2);   assert(!(r == l2));    std::cout << l << '\n';   std::cout << r << '\n';   std::cout << x << '\n'; } 

without parenthesis @ line:

    text = new char[len + 1]; 

i assert @ line

assert(strcmp("helloworld", x.gettext()) == 0); 

a.out: main.cpp:83: int main(): assertion `strcmp("hello", l.gettext()) == 0' failed.

and without asserts sanitizer error:

==29167==error: addresssanitizer: heap-buffer-overflow on address 0x60200000eff6 @ pc 0x7f0f48d679cb bp 0x7fffb3df3820 sp 0x7fffb3df2fd0 read of size 7 @ 0x60200000eff6 thread t0     #0 0x7f0f48d679ca in __interceptor_strlen (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x6d9ca)     #1 0x7f0f48a9f938 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xb2938)     #2 0x40114a in operator<<(std::ostream&, line const&) /home/xxx/programming/c/xxx/main.cpp:72     #3 0x401276 in main /home/xxx/programming/c/xxx/main.cpp:88     #4 0x7f0f48432ec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)     #5 0x400ed8  (/home/xxx/programming/c/xxx/a.out+0x400ed8)  0x60200000eff6 located 0 bytes right of 6-byte region [0x60200000eff0,0x60200000eff6) allocated thread t0 here:     #0 0x7f0f48d8f30a in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x9530a)     #1 0x4014fd in line::line(char const*) /home/xxx/programming/c/xxx/main.cpp:11     #2 0x40121d in main /home/xxx/programming/c/xxx/main.cpp:78     #3 0x7f0f48432ec4 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)  summary: addresssanitizer: heap-buffer-overflow ??:0 __interceptor_strlen shadow bytes around buggy address:   0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 00 03 =>0x0c047fff9df0: fa fa fd fd fa fa 06 fa fa fa 06 fa fa fa[06]fa   0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa shadow byte legend (one shadow byte represents 8 application bytes):   addressable:           00   partially addressable: 01 02 03 04 05 06 07    heap left redzone:       fa   heap right redzone:      fb   freed heap region:       fd   stack left redzone:      f1   stack mid redzone:       f2   stack right redzone:     f3   stack partial redzone:   f4   stack after return:      f5   stack use after scope:   f8   global redzone:          f9   global init order:       f6   poisoned user:        f7   container overflow:      fc   array cookie:            ac   intra object redzone:    bb   asan internal:           fe ==29167==aborting 

why need initialize memory? (equivalent of using std::fill)

the problem usage of std::strncat. appends line end of current line. end of current line determined finding terminating 0 in current line. if not initialize data, end many random characters unlikely include 0 first element (therefore treated pre-existing data , cause buffer overflow).

use strncpy/strcpy copy first line:

unsigned newlen = lhs.getlen() + rhs.getlen(); char* newc = new char[newlen + 1]; std::strncpy(newc, lhs.gettext(), lhs.getlen() + 1); std::strncat(newc, rhs.gettext(), rhs.getlen() + 1); 

Comments

Popular posts from this blog

sublimetext3 - what keyboard shortcut is to comment/uncomment for this script tag in sublime -

java - No use of nillable="0" in SOAP Webservice -

ubuntu - Laravel 5.2 quickstart guide gives Not Found Error -