Logfind Attempt, Memory Leaks?


#1

Below is my attempt at the logfind project from exercise number 26. It seems to be working, but I’m wondering if there’s any way to make it smaller or more efficient… I’d really appreciate any suggestions.

The other problem is that Valgrind says there are two memory leaks, but I’m pretty sure I freed everything. Any ideas where this is occurring?

==16550== Memcheck, a memory error detector
==16550== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16550== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16550== Command: ./logfind felix
==16550== 
[/etc/testlogs/logwithfelix.log] [010101] Felix is terrible
[/etc/testlogs/logwithfelix.log] [020202] Felix is awesome
==16550== 
==16550== HEAP SUMMARY:
==16550==     in use at exit: 134 bytes in 3 blocks
==16550==   total heap usage: 16 allocs, 13 frees, 48,030 bytes allocated
==16550== 
==16550== 21 bytes in 1 blocks are definitely lost in loss record 1 of 2
==16550==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16550==    by 0x108E8D: get_file (logfind.c:32)
==16550==    by 0x1093E1: main (logfind.c:125)
==16550== 
==16550== 113 bytes in 2 blocks are definitely lost in loss record 2 of 2
==16550==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16550==    by 0x108E8D: get_file (logfind.c:32)
==16550==    by 0x109079: do_finding (logfind.c:68)
==16550==    by 0x109308: do_globbing (logfind.c:113)
==16550==    by 0x1093FC: main (logfind.c:127)
==16550== 
==16550== LEAK SUMMARY:
==16550==    definitely lost: 134 bytes in 3 blocks
==16550==    indirectly lost: 0 bytes in 0 blocks
==16550==      possibly lost: 0 bytes in 0 blocks
==16550==    still reachable: 0 bytes in 0 blocks
==16550==         suppressed: 0 bytes in 0 blocks
==16550== 
==16550== For counts of detected and suppressed errors, rerun with: -v
==16550== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
#define _GNU_SOURCE // Needed to get strcasestr()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <glob.h>
#include "dbg.h"

#define HOME "/home/felix"

int is_empty(const char *string) {
    int i = 0;

    for (i = 0; i < strlen(string); i++) {
        if (!isspace(string[i])) return 0;
    }

    return 1;
}

char *get_file(char *location) {
    if (is_empty(location)) return "";

    FILE *file = fopen(location, "rb");
    check(file, "The file %s couldn't be opened", location);

    fseek(file, 0, SEEK_END);
    long size = ftell(file); // Get size of memory needed to store file content
    rewind(file);

    char *content = malloc(size + 1); // Allocate memory for file content
    check_mem(content);

    fread(content, size, 1, file); // Read file into memory buffer
    fclose(file);
    content[size] = '\0';

    return content;
error:
    exit(1);
}

int has_and_or(char *string, int argc, char *argv[]) {
    int i = 0;
    int found = -1;
    int or = 0;

    for (i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-o") == 0) {
            or = 1;
            continue;
        }
        int found_this_time = strcasestr(string, argv[i]) ? 1 : 0;
        if (or) {
            found = found == -1 ? 0 : found;
            found = found || found_this_time;
        } else {
            found = found == -1 ? 1 : found;
            found = found && found_this_time;
        }
    }

    return found;
}

void do_finding(char *file, int argc, char *argv[]) {
    char *logs = get_file(file);
    char *line;

    while ((line = strsep(&logs, "\n"))) {
        if (is_empty(line)) continue;
        if (has_and_or(line, argc, argv)) {
            printf("[");
            printf("\x1B[31m"); // Color red
            printf("%s", file);
            printf("\x1B[0m"); // Color normal
            printf("] ");
            printf("%s\n", line);
        }
    }

    free(logs);
}

char *clean_glob_err(int rc) {
    switch(rc) {
        case GLOB_ABORTED:
            return "Filesystem problem";
        case GLOB_NOMATCH:
            return "No matches";
        case GLOB_NOSPACE:
            return "Out of memory";
        default:
            return "Unknown error";
    }
}

int glob_warn(const char *path, int _) {
    log_warn("Trouble with glob: %s", path);
    return 0;
}

void do_globbing(char *glob_in, int argc, char *argv[]) {
    if (is_empty(glob_in)) return;

    glob_t results;
    int i = 0;
    int rc = glob(glob_in, 0, glob_warn, &results);
    check(rc == 0, "Bad glob: %s (%s)", glob_in, clean_glob_err(rc));

    for (i = 0; i < results.gl_pathc; i++) {
        do_finding(results.gl_pathv[i], argc, argv);
    }

    globfree(&results);
error:
    globfree(&results); // Free the glob results
    return;
}

int main(int argc, char *argv[]) {
    check(argc >= 2, "You must specify at least one search term");

    char *config = get_file(HOME "/.logfind");
    char *glob_in;
    while ((glob_in = strsep(&config, "\n"))) do_globbing(glob_in, argc, argv);
    free(config);

    return 0;
error:
    if (config) free(config);
    return 1;
}

#2

I think that’s pretty decent for now. If you want to try and improve it try handing it garbage. You can use /dev/random to create a garbage file and see what it does.


#3

It actually seems to take garbage surprisingly well:

I didn’t expect that. I’m still trying to figure out the memory leak, though… I’m not totally sure why it’s happening.


#4

Valgrind with lots of options is going to help you find that. I don’t remember them off my head but it should be in the docs.


#5

I tried running with a bunch of options, although the documentation isn’t seeming to help very much. It still reports the memory leaks. I don’t get how I can allocate memory, free it (without any errors, mind you), and then still have a memory leak!


#6

Welp! If you can’t figure out the exact line number in your code where you allocated the RAM then I’m at a loss as to where it’s from. I’d say, unless you can run the offending lines in a massive loop to see if you run out then it’s probably not an important amount of memory and just gets cleaned up when you exit. Try moving on and come back to this later.


#7

I know exactly exactly where I allocate the memory (line 32), It’s just that I also free it on lines 83 and 128, but the memory is still apparently leaking. I’m confuddled.


#8

Yeah, I guess I’ll just move on and come back to this…