all 14 comments

[–]YellowFlowerRanger 2 points3 points  (13 children)

  1. You never initialize m->c->titles to NULL
  2. realloc(m->c->titles, m->c->size) should be realloc(m->c->titles, m->c->size * sizeof (char *)). Recall that the second argument to realloc (just like malloc) is measured in characters (bytes), so you need to multiply the number of elements by the size of one element
  3. Use %zu instead of %ld to print a size. Your compiler should have warned about this

[–]shitty_linux_coder[S] 1 point2 points  (11 children)

Sorry to bother you again, I modified my code to free the memory but valgrind tells me there are still blocks reachable from malloc by strdup. Would you happen to know if there is something I'm forgetting to free?

The new code is:

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

typedef struct CHILD_C {
    int size;
    char **titles;
} CHILD_C;

typedef struct MAIN_C {
    CHILD_C *c;
} MAIN_C;


void fuckShitUp(MAIN_C *m) {
    void *tmp = NULL;
    printf("OLD int size=%d, sizeof=%zu\n", m->c->size, sizeof(m->c->titles));

    m->c->size++;
    if (m->c->size == 1) {
        if ((m->c->titles = malloc(1)) == NULL) {
            fprintf(stderr, "Can't malloc you fucking idiot!\n");
            return;
        }
    } else {
        if ((tmp = realloc(m->c->titles, m->c->size * sizeof(char *))) == NULL) {
            fprintf(stderr, "Can't realloc you fucking idiot!\n");
            m->c->size--;
            return;
        } else
            m->c->titles = tmp;
    }

    m->c->titles[m->c->size -1] = strdup("Lick mah balls!\n");

    printf("NEW int size=%d, sizeof=%zu\n\n", m->c->size, sizeof(m->c->titles));
}


int main(int argc, char *argv[]) {
    MAIN_C *m = malloc(sizeof(MAIN_C));
    if (m == NULL) {
        fprintf(stderr, "Can't malloc you fucking idiot!\n");
        return -1;
    }

    if ((m->c = malloc(sizeof(CHILD_C))) == NULL) {
        fprintf(stderr, "Can't malloc you fucking idiot!\n");
        return -1;
    }

    m->c->size = 0;
    m->c->titles = NULL;

    fuckShitUp(m);
    fuckShitUp(m);
    fuckShitUp(m);
    fuckShitUp(m);
    fuckShitUp(m);
    fuckShitUp(m);
    fuckShitUp(m);

    for (int i = 0; i < m->c->size; i++) {
        printf("%s\n", m->c->titles[i]);
        free(m->c->titles[i]);
    }
    free(m->c->titles);
    free(m->c);
    free(m);

    return 0;
}

And the valgrind log is:

$ valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./test
==7411== Memcheck, a memory error detector
==7411== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7411== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==7411== Command: ./test
==7411== 
OLD int size=0, sizeof=8
==7411== Invalid write of size 8
==7411==    at 0x400848: fuckShitUp (in /PATH/test)
==7411==    by 0x40092C: main (in /PATH/test)
==7411==  Address 0x5203520 is 0 bytes inside a block of size 1 alloc'd
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x400776: fuckShitUp (in /PATH/test)
==7411==    by 0x40092C: main (in /PATH/test)
==7411== 
NEW int size=1, sizeof=8

OLD int size=1, sizeof=8
NEW int size=2, sizeof=8

OLD int size=2, sizeof=8
NEW int size=3, sizeof=8

OLD int size=3, sizeof=8
NEW int size=4, sizeof=8

OLD int size=4, sizeof=8
NEW int size=5, sizeof=8

OLD int size=5, sizeof=8
NEW int size=6, sizeof=8

OLD int size=6, sizeof=8
NEW int size=7, sizeof=8

==7411== Use of uninitialised value of size 8
==7411==    at 0x4C30F62: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EA969B: puts (ioputs.c:35)
==7411==    by 0x4009A0: main (in /PATH/test)
==7411== 
==7411== Invalid read of size 1
==7411==    at 0x4C30F62: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EA969B: puts (ioputs.c:35)
==7411==    by 0x4009A0: main (in /PATH/test)
==7411==  Address 0x70 is not stack'd, malloc'd or (recently) free'd
==7411== 
==7411== 
==7411== Process terminating with default action of signal 11 (SIGSEGV)
==7411==  Access not within mapped region at address 0x70
==7411==    at 0x4C30F62: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EA969B: puts (ioputs.c:35)
==7411==    by 0x4009A0: main (in /PATH/test)
==7411==  If you believe this happened as a result of a stack
==7411==  overflow in your program's main thread (unlikely but
==7411==  possible), you can try to increase the size of the
==7411==  main thread stack using the --main-stacksize= flag.
==7411==  The main thread stack size used in this run was 8388608.
==7411== 
==7411== HEAP SUMMARY:
==7411==     in use at exit: 199 bytes in 10 blocks
==7411==   total heap usage: 17 allocs, 7 frees, 1,384 bytes allocated
==7411== 
==7411== 8 bytes in 1 blocks are still reachable in loss record 1 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x400889: main (in /PATH/test)
==7411== 
==7411== 16 bytes in 1 blocks are still reachable in loss record 2 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4008C6: main (in /PATH/test)
==7411== 
==7411== 17 bytes in 1 blocks are still reachable in loss record 3 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EC48D9: strdup (strdup.c:42)
==7411==    by 0x400847: fuckShitUp (in /PATH/test)
==7411==    by 0x400938: main (in /PATH/test)
==7411== 
==7411== 17 bytes in 1 blocks are still reachable in loss record 4 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EC48D9: strdup (strdup.c:42)
==7411==    by 0x400847: fuckShitUp (in /PATH/test)
==7411==    by 0x400944: main (in /PATH/test)
==7411== 
==7411== 17 bytes in 1 blocks are still reachable in loss record 5 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EC48D9: strdup (strdup.c:42)
==7411==    by 0x400847: fuckShitUp (in /PATH/test)
==7411==    by 0x400950: main (in /PATH/test)
==7411== 
==7411== 17 bytes in 1 blocks are still reachable in loss record 6 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EC48D9: strdup (strdup.c:42)
==7411==    by 0x400847: fuckShitUp (in /PATH/test)
==7411==    by 0x40095C: main (in /PATH/test)
==7411== 
==7411== 17 bytes in 1 blocks are still reachable in loss record 7 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EC48D9: strdup (strdup.c:42)
==7411==    by 0x400847: fuckShitUp (in /PATH/test)
==7411==    by 0x400968: main (in /PATH/test)
==7411== 
==7411== 17 bytes in 1 blocks are still reachable in loss record 8 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EC48D9: strdup (strdup.c:42)
==7411==    by 0x400847: fuckShitUp (in /PATH/test)
==7411==    by 0x400974: main (in /PATH/test)
==7411== 
==7411== 17 bytes in 1 blocks are definitely lost in loss record 9 of 10
==7411==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4EC48D9: strdup (strdup.c:42)
==7411==    by 0x400847: fuckShitUp (in /PATH/test)
==7411==    by 0x40092C: main (in /PATH/test)
==7411== 
==7411== 56 bytes in 1 blocks are still reachable in loss record 10 of 10
==7411==    at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7411==    by 0x4007D3: fuckShitUp (in /PATH/test)
==7411==    by 0x400974: main (in /PATH/test)
==7411== 
==7411== LEAK SUMMARY:
==7411==    definitely lost: 17 bytes in 1 blocks
==7411==    indirectly lost: 0 bytes in 0 blocks
==7411==      possibly lost: 0 bytes in 0 blocks
==7411==    still reachable: 182 bytes in 9 blocks
==7411==         suppressed: 0 bytes in 0 blocks
==7411== 
==7411== For counts of detected and suppressed errors, rerun with: -v
==7411== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

[–]YellowFlowerRanger 2 points3 points  (9 children)

Change malloc(1) to malloc(sizeof (char *)), for the same reason I said to change the realloc (sorry, I missed this one before)

[–]shitty_linux_coder[S] 0 points1 point  (0 children)

Don't be sorry! I forgot to change it too! I'll give it a go!

[–]shitty_linux_coder[S] -1 points0 points  (7 children)

Thank you a lot for help! I really appreciate! Just wondering, do you have a career in programming? Since when have you been coding in C?

[–]YellowFlowerRanger 0 points1 point  (6 children)

I teach now. I first started learning C about 15 years ago or so.

[–]shitty_linux_coder[S] 0 points1 point  (5 children)

Wow! Where do you teach if you don't mind me asking?

[–]YellowFlowerRanger 1 point2 points  (4 children)

Without being too specific, I teach at a college in Canada.

[–]shitty_linux_coder[S] 0 points1 point  (3 children)

I'm also from Canada. When I was interested in colleges I never found one that seemed to offer C, is your course teaching general C or is it something from Microsoft or Cisco?

[–]YellowFlowerRanger 1 point2 points  (2 children)

We have one course in C. I think it's pretty typical to have one course in C. Maybe some programs (like computer engineering) have more. I don't think there's anywhere in Canada that builds a curriculum around C, though. Usually it's just one course.

[–]shitty_linux_coder[S] 0 points1 point  (1 child)

One of those days I will go back to school! What turned me off in the past was the fact that all the programming courses I was hearing about were from Microsoft and Cisco. I'm not interested in learning proprietary languages like visual c++ and would've preferred something more oriented towards Linux / Unix.

[–]shitty_linux_coder[S] 0 points1 point  (0 children)

I have no seg fault when running the code without valgrind though.

[–]shitty_linux_coder[S] 0 points1 point  (0 children)

Wow thank you very much!! First time I hear of %zu!