Home > Software engineering >  IOT instruction when freeing a malloc'ed array
IOT instruction when freeing a malloc'ed array

Time:01-15

I am developing a program that is supposed to take a string as a parameter and display the number of occurrences of each word in their order of appearance.

I have a problem when the string contains more than 3 different words.

The error:

double free or corruption (out)
[1]    189175 IOT instruction (core dumped)  ./test "like test test love love like pop"

valgrind:

==189553== Memcheck, a memory error detector
==189553== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==189553== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==189553== Command: ./test like\ test\ test\ love\ love\ like\ pop
==189553== Parent PID: 185694
==189553== 
==189553== Invalid write of size 8
==189553==    at 0x10930B: handle_word (test.c:32)
==189553==    by 0x1093F6: count_word_occurrences (test.c:49)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74048 is 0 bytes after a block of size 8 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x10938B: count_word_occurrences (test.c:43)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== Invalid write of size 4
==189553==    at 0x109324: handle_word (test.c:33)
==189553==    by 0x1093F6: count_word_occurrences (test.c:49)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74094 is 0 bytes after a block of size 4 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x109399: count_word_occurrences (test.c:44)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== Invalid read of size 8
==189553==    at 0x10925B: word_exists (test.c:19)
==189553==    by 0x1092BE: handle_word (test.c:27)
==189553==    by 0x1093F6: count_word_occurrences (test.c:49)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74048 is 0 bytes after a block of size 8 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x10938B: count_word_occurrences (test.c:43)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== Invalid read of size 4
==189553==    at 0x1092DC: handle_word (test.c:29)
==189553==    by 0x1093F6: count_word_occurrences (test.c:49)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74094 is 0 bytes after a block of size 4 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x109399: count_word_occurrences (test.c:44)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== Invalid write of size 4
==189553==    at 0x1092E1: handle_word (test.c:29)
==189553==    by 0x1093F6: count_word_occurrences (test.c:49)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74094 is 0 bytes after a block of size 4 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x109399: count_word_occurrences (test.c:44)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== Invalid read of size 4
==189553==    at 0x10943E: count_word_occurrences (test.c:58)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74094 is 0 bytes after a block of size 4 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x109399: count_word_occurrences (test.c:44)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== Invalid read of size 8
==189553==    at 0x109453: count_word_occurrences (test.c:58)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74048 is 0 bytes after a block of size 8 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x10938B: count_word_occurrences (test.c:43)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== Invalid read of size 8
==189553==    at 0x109499: count_word_occurrences (test.c:61)
==189553==    by 0x109523: main (test.c:75)
==189553==  Address 0x4a74048 is 0 bytes after a block of size 8 alloc'd
==189553==    at 0x4841888: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==189553==    by 0x10938B: count_word_occurrences (test.c:43)
==189553==    by 0x109523: main (test.c:75)
==189553== 
==189553== 
==189553== HEAP SUMMARY:
==189553==     in use at exit: 0 bytes in 0 blocks
==189553==   total heap usage: 10 allocs, 10 frees, 1,070 bytes allocated
==189553== 
==189553== All heap blocks were freed -- no leaks are possible
==189553== 
==189553== For lists of detected and suppressed errors, rerun with: -s
==189553== ERROR SUMMARY: 25 errors from 8 contexts (suppressed: 0 from 0)

Code:

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

bool is_separator(char c)
{
    return c == ' ' || c == '\0' || c == '\t';
}

char *extract_word(char *str, size_t start, size_t len)
{
    char *curr_word = malloc(len   1);
    strncpy(curr_word, str   start, len);
    curr_word[len] = '\0';
    return curr_word;
}

int word_exists(char **words, size_t word_count, char *word)
{
    for (size_t i = 0; i < word_count; i  ) {
        if (strcmp(words[i], word) == 0) {
            return i;
        }
    }
    return -1;
}

void handle_word(char **words, int *counts, size_t *word_count, char *curr_word)
{
    int found_index = word_exists(words, *word_count, curr_word);
    if (found_index != -1) {
        counts[found_index]  ;
        free(curr_word);
    } else {
        words[*word_count] = curr_word;
        counts[*word_count] = 1;
        (*word_count)  ;
    }
}

size_t count_word_occurrences(char *str)
{
    size_t len = strlen(str);
    size_t curr_word_start = 0;
    size_t curr_word_len = 0;
    size_t word_count = 0;
    char **words = malloc(sizeof(char*));
    int *counts = malloc(sizeof(int));
    size_t i = 0;
    while (i <= len) {
        if (is_separator(str[i])) {
            char *curr_word = extract_word(str, curr_word_start, curr_word_len);
            handle_word(words, counts, &word_count, curr_word);
            curr_word_start = i   1;
            curr_word_len = 0;
        } else {
            curr_word_len  ;
        }
        i  ;
    }
    for (size_t i = 0; i < word_count; i  ) {
        printf("%s %d\n", words[i], counts[i]);
    }
    for (size_t i = 0; i < word_count; i  ) {
        free(words[i]);
    }
    free(words);
    free(counts);
    return 0;
}


int main(int argc, char **argv)
{
    if (argc != 2) {
        printf("\n");
        return 0;
    }
    char *str = argv[1];
    count_word_occurrences(str);
    return 0;
}

Thanks in advance.

CodePudding user response:

Thank you all,

The error came from the malloc() linked to the double dimensional array :

char **words = malloc(sizeof(char*));

So I replaced the line with :

char **words = malloc(len * sizeof(char*))

And it's ok.

  • Related