"free(): invalid pointer" in very strange situation

I have to similars programs but the second one doesn't work

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  #include <iostream>
#include <fstream>

typedef const char* str;
typedef unsigned int uint;

int strsSize(str);
str strCopy(char*, str);

template <typename ...Arg> int strsSize(str, Arg...);
template <typename ...Arg> str strCopy(char*, str, Arg...);
template <typename ...Arg> str strCat(Arg...); 

int main(int argc, str* argv) {
    if(argc == 1) {
        std::cout << "Project name argument is empty";
        return -1;
    }
    else {
        str dir       = strCat("mkdir ", argv[1]),
            src       = strCat("mkdir ", argv[1], "/src"),
            bin       = strCat("mkdir ", argv[1], "/bin"),
            lib       = strCat("mkdir ", argv[1], "/lib"),
            include   = strCat("mkdir ", argv[1], "/include"),
            make      = strCat(argv[1], "/Makefile"),
            creatMake = strCat("touch ", make),
            mainCpp   = strCat(argv[1], "/src/main.cpp"),
            creatMain = strCat("touch ", mainCpp);

        system(dir);
        delete [] dir;
        system(src);
        delete [] src;
        system(bin);
        delete [] bin;
        system(lib);
        delete [] lib;
        system(include);
        delete [] include;

        system(creatMake);
        delete [] creatMake;

        system(creatMain);
        delete [] creatMain;

        std::ofstream makeFile(make); 
        delete [] make; 

        makeFile << "CXX     := g++\n"
                 << "FlAGS   := -s -O3\n"
                 << "INCLUDE := -Iinclude\n"
                 << "SRC     := src\n"
                 << "BIN     := bin\n"
                 << "LIB     := -Llib\n"
                 << "LIBS    :=\n"
                 << "NAME    := " << argv[1]
                 << "\n\n\nall: $(BIN)/$(NAME)\n"
                 << "\nrun: all\n"
                 << "\t$(BIN)/$(NAME)"
                 << "\n$(BIN)/$(NAME): $(SRC)/*.cpp\n"
                 << "\t$(CXX) $(FLAGS) $(INCLUDE) $^ -o $@ $(LIBS)";

        std::ofstream mainFile(mainCpp);
        delete [] mainCpp;

        mainFile << "int main() {\n"
                 << "\treturn 0;\n"
                 << "}";
    }

    return 0;
}


int strsSize(str s) {
    uint l = 0;
    while(s[l] != '\0') {
        ++l;
    }
    return l; 
}

template <typename ...Arg> int strsSize(str s, Arg... args) {
    uint l = 0;
    while(s[l] != '\0') {
        ++l;
    }
    return l + strsSize(args...); 
}

str strCopy(char* s, str sCopy) {   
    uint l = 0, i = 0;
    while(s[i] != '\0') {
        ++i;
    }
    while(sCopy[l] != '\0') {
        s[l + i] = sCopy[l];
        ++l;
    }
    s[++l + i] = '\0';
    return s; 
}

template <typename ...Arg> str strCopy(char* s, str sCopy, Arg... copyArgs) {
    strCopy(s, sCopy);
    return strCopy(s, copyArgs...);
}

template <typename ...Arg> str strCat(Arg... strs) {
    char* result = new char[strsSize(strs...) + 1]{};
    strCopy(result, strs...);
    return str(result);
}



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <fstream>

typedef const char* str;
typedef unsigned int uint;

int strsSize(str);
str strCopy(char*, str);

template <typename ...Arg> int strsSize(str, Arg...);
template <typename ...Arg> str strCopy(char*, str, Arg...);
template <typename ...Arg> str strCat(Arg...); 

int main(int argc, str* argv) {
    if(argc == 1) {
        std::cout << "Project name argument is empty";
        return -1;
    }
    else {
        str dir       = strCat("mkdir ", argv[1]),
            src       = strCat("mkdir ", argv[1], "/src"),
            bin       = strCat("mkdir ", argv[1], "/bin"),
            lib       = strCat("mkdir ", argv[1], "/lib"),
            include   = strCat("mkdir ", argv[1], "/include");
            
        system(dir);
        delete [] dir;
        system(src);
        delete [] src;
        system(bin);
        delete [] bin;
        system(lib);
        delete [] lib;
        system(include);
        delete [] include;

        str make      = strCat(argv[1], "/Makefile"),
            creatMake = strCat("touch ", make);
        
        system(creatMake);
        delete [] creatMake;

        std::ofstream makeFile(make); 
        delete [] make; 

        makeFile << "CXX     := g++\n"
                 << "FlAGS   := -s -O3\n"
                 << "INCLUDE := -Iinclude\n"
                 << "SRC     := src\n"
                 << "BIN     := bin\n"
                 << "LIB     := -Llib\n"
                 << "LIBS    :=\n"
                 << "NAME    := " << argv[1]
                 << "\n\n\nall: $(BIN)/$(NAME)\n"
                 << "\nrun: all\n"
                 << "\t$(BIN)/$(NAME)"
                 << "\n$(BIN)/$(NAME): $(SRC)/*.cpp\n"
                 << "\t$(CXX) $(FLAGS) $(INCLUDE) $^ -o $@ $(LIBS)";

        str mainCpp   = strCat(argv[1], "/src/main.cpp"),
            creatMain = strCat("touch ", mainCpp);
        
        system(creatMain);
        delete [] creatMain;

        std::ofstream mainFile(mainCpp);
        delete [] mainCpp;

        mainFile << "int main() {\n"
                 << "\treturn 0;\n"
                 << "}";
    }

    return 0;
}


int strsSize(str s) {
    uint l = 0;
    while(s[l] != '\0') {
        ++l;
    }
    return l; 
}

template <typename ...Arg> int strsSize(str s, Arg... args) {
    uint l = 0;
    while(s[l] != '\0') {
        ++l;
    }
    return l + strsSize(args...); 
}

str strCopy(char* s, str sCopy) {   
    uint l = 0, i = 0;
    while(s[i] != '\0') {
        ++i;
    }
    while(sCopy[l] != '\0') {
        s[l + i] = sCopy[l];
        ++l;
    }
    s[++l + i] = '\0';
    return s; 
}

template <typename ...Arg> str strCopy(char* s, str sCopy, Arg... copyArgs) {
    strCopy(s, sCopy);
    return strCopy(s, copyArgs...);
}

template <typename ...Arg> str strCat(Arg... strs) {
    char* result = new char[strsSize(strs...) + 1]{};
    strCopy(result, strs...);
    return str(result);
}

I get
free(): invalid pointer
I replaced all your system() with std::cout and got this.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
$ g++ -g -std=c++11 -g baz.cpp
$ valgrind ./a.out wibbler
==6299== Memcheck, a memory error detector
==6299== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6299== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==6299== Command: ./a.out wibbler
==6299== 
==6299== Invalid write of size 1
==6299==    at 0x400D73: strCopy(char*, char const*) (baz.cpp:87)
==6299==    by 0x400F4A: char const* strCopy<char const*>(char*, char const*, char const*) (baz.cpp:93)
==6299==    by 0x400E3E: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:98)
==6299==    by 0x40091B: main (baz.cpp:22)
==6299==  Address 0x5ab6c8e is 0 bytes after a block of size 14 alloc'd
==6299==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6299==    by 0x400E00: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:97)
==6299==    by 0x40091B: main (baz.cpp:22)
==6299== 
==6299== Invalid write of size 1
==6299==    at 0x400D73: strCopy(char*, char const*) (baz.cpp:87)
==6299==    by 0x400F4A: char const* strCopy<char const*>(char*, char const*, char const*) (baz.cpp:93)
==6299==    by 0x400FDC: char const* strCopy<char const*, char const*>(char*, char const*, char const*, char const*) (baz.cpp:93)
==6299==    by 0x400EC2: char const* strCat<char const*, char const*, char const*>(char const*, char const*, char const*) (baz.cpp:98)
==6299==    by 0x40093C: main (baz.cpp:23)
==6299==  Address 0x5ab6ce2 is 0 bytes after a block of size 18 alloc'd
==6299==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6299==    by 0x400E83: char const* strCat<char const*, char const*, char const*>(char const*, char const*, char const*) (baz.cpp:97)
==6299==    by 0x40093C: main (baz.cpp:23)
==6299== 
dir=mkdir wibbler=
src=mkdir wibbler/src=
bin=mkdir wibbler/bin=
lib=mkdir wibbler/lib=
include=mkdir wibbler/include=
==6299== Invalid write of size 1
==6299==    at 0x400D73: strCopy(char*, char const*) (baz.cpp:87)
==6299==    by 0x400F4A: char const* strCopy<char const*>(char*, char const*, char const*) (baz.cpp:93)
==6299==    by 0x400E3E: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:98)
==6299==    by 0x400B41: main (baz.cpp:39)
==6299==  Address 0x5ab72a1 is 0 bytes after a block of size 17 alloc'd
==6299==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6299==    by 0x400E00: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:97)
==6299==    by 0x400B41: main (baz.cpp:39)
==6299== 
==6299== Invalid write of size 1
==6299==    at 0x400D73: strCopy(char*, char const*) (baz.cpp:87)
==6299==    by 0x400F4A: char const* strCopy<char const*>(char*, char const*, char const*) (baz.cpp:93)
==6299==    by 0x400E3E: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:98)
==6299==    by 0x400B56: main (baz.cpp:40)
==6299==  Address 0x5ab7307 is 0 bytes after a block of size 23 alloc'd
==6299==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6299==    by 0x400E00: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:97)
==6299==    by 0x400B56: main (baz.cpp:40)
==6299== 
creatMake=touch wibbler/Makefile=
make=wibbler/Makefile=
==6299== Invalid write of size 1
==6299==    at 0x400D73: strCopy(char*, char const*) (baz.cpp:87)
==6299==    by 0x400F4A: char const* strCopy<char const*>(char*, char const*, char const*) (baz.cpp:93)
==6299==    by 0x400E3E: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:98)
==6299==    by 0x400C0E: main (baz.cpp:48)
==6299==  Address 0x5ab7365 is 0 bytes after a block of size 21 alloc'd
==6299==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6299==    by 0x400E00: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:97)
==6299==    by 0x400C0E: main (baz.cpp:48)
==6299== 
==6299== Invalid write of size 1
==6299==    at 0x400D73: strCopy(char*, char const*) (baz.cpp:87)
==6299==    by 0x400F4A: char const* strCopy<char const*>(char*, char const*, char const*) (baz.cpp:93)
==6299==    by 0x400E3E: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:98)
==6299==    by 0x400C23: main (baz.cpp:49)
==6299==  Address 0x5ab73cb is 0 bytes after a block of size 27 alloc'd
==6299==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6299==    by 0x400E00: char const* strCat<char const*, char const*>(char const*, char const*) (baz.cpp:97)
==6299==    by 0x400C23: main (baz.cpp:49)
==6299== 
creatMain=touch wibbler/src/main.cpp=
mainCpp=wibbler/src/main.cpp=
==6299== 
==6299== HEAP SUMMARY:
==6299==     in use at exit: 72,704 bytes in 1 blocks
==6299==   total heap usage: 11 allocs, 10 frees, 73,906 bytes allocated
==6299== 
==6299== LEAK SUMMARY:
==6299==    definitely lost: 0 bytes in 0 blocks
==6299==    indirectly lost: 0 bytes in 0 blocks
==6299==      possibly lost: 0 bytes in 0 blocks
==6299==    still reachable: 72,704 bytes in 1 blocks
==6299==         suppressed: 0 bytes in 0 blocks
==6299== Rerun with --leak-check=full to see details of leaked memory
==6299== 
==6299== For counts of detected and suppressed errors, rerun with: -v
==6299== ERROR SUMMARY: 9 errors from 6 contexts (suppressed: 0 from 0) 


You seem to have a lot of off-by-1 in calculating the amount of space needed for your strings.
In this function, you increment l one-too-many times when null-terminating:

1
2
3
4
5
6
7
8
9
10
11
12
str strCopy(char* s, str sCopy) {   
    uint l = 0, i = 0;
    while(s[i] != '\0') {
        ++i;
    }
    while(sCopy[l] != '\0') {
        s[l + i] = sCopy[l];
        ++l;
    }
    s[++l + i] = '\0';  // shouldn't increment l here
    return s;
}


It should be mentioned that C++ is a bad choice for this kind of thing. It would be much easier and clearer in bash.
Last edited on
Thanks, guys. I'm feeling so foolish now. I thought the error was somewhere in
main
.
Last edited on
it would be much easier and clearer with std::string and raw literals.
I know. I just wanted to train my skills. But now I'm wondering why this function worked perfectly before when I was testing it and I didn't get such error when I freed the memory.
> But now I'm wondering why this function worked perfectly before when I was testing it
> and I didn't get such error when I freed the memory.
That's the nature of the beast.
Overwriting someone else's memory is undefined behaviour, not insta-death.

To preserve memory alignment, and reduce fragmentation, small allocations are rounded up in size. So you might ask for 10 bytes but the allocator will give you 16. You shouldn't use any of the last 6, but then again no-one else will either. It's tough to spot these without tools like valgrind, because nothing ever seems to go wrong.

It's only when you start having longer strings, and string lengths close to alignment boundary sizes that your off-by-1 start to matter.
Topic archived. No new replies allowed.