Question

I fairly old to C programming (even though I haven't programmed in C for many years) but I am utterly stuck now. I have two source files:

main.c

#include <stdio.h>
#include "inputFunction.h"

int main(int argc, char** argv) {
    char *invoiceFile=NULL, *inputFile=NULL, *configFile=NULL;
    getInput(argc, argv, &invoiceFile, &inputFile, &configFile);
    if(invoiceFile!=NULL){
        free(invoiceFile);
    }
    if(inputFile!=NULL){
        free(inputFile);
    }
    if(configFile!=NULL){
        free(configFile);
    }
    return (EXIT_SUCCESS);
}

and inputFunction.c

#include "inputFunction.h"

int getInput(int argc, char** argv, char **invoiceFile, char **inputFile, char **configFile) {
    int i;
    if (argc != 3 && argc != 5 && argc != 7) {
        inputError();
        return 1;
    } else {
        for (i = 1; i < argc; i += 2) {
            if (!strcmp(argv[i], "-o")) {
                if (*invoiceFile == NULL) {
                    if (((*invoiceFile) = malloc((strnlen(argv[i + 1], 256) + 1) * sizeof (char))) == NULL) {
                        perror("A problem occurred when allocating memory.\n");
                        return 1;
                    }
                    strncpy((*invoiceFile), argv[i + 1], 256);
                } else {
                    inputError();
                    return 1;
                }
            }
            if (!strcmp(argv[i], "-i")) {
                if (*inputFile == NULL) {
                    if (((*inputFile) = malloc((strnlen(argv[i + 1], 256) + 1) * sizeof (char))) == NULL) {
                        perror("A problem occurred when allocating memory.\n");
                        return 1;
                    }
                    strncpy((*inputFile), argv[i + 1], 256);
                } else {
                    inputError();
                    return 1;
                }
            }
            if (!strcmp(argv[i], "-c")) {
                if (*configFile == NULL) {
                    if (((*configFile) = malloc((strnlen(argv[i + 1], 256) + 1) * sizeof (char))) == NULL) {
                        perror("A problem occurred when allocating memory.\n");
                        return 1;
                    }
                    strncpy((*configFile), argv[i + 1], 256);
                } else {
                    inputError();
                    return 1;
                }
            }
        }
    }
    if (*invoiceFile == NULL) {
        inputError();
        return 1;
    }
    return 0;
}

void inputError() {
    printf("\nInvalid input\n");
    printf("Correct input parameters are:\n");
    printf("-o InvoiceFile\n");
    printf("-i InputFile (optional)\n");
    printf("-c configFile (optional)\n\n\n");
}

and a header file:

inputFunction.h

#ifndef INPUTFUNCTION_H
#define INPUTFUNCTION_H

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

int getInput(int argc, char** argv, char **invoiceFile, char **inputFile, char **configFile);

void inputError();

#endif  /* INPUTFUNCTION_H */

The program gets 3 parameters from the command line with a filename after each one (only one is obligatory the "-o" along with its filename). So when I put all (total 6) of them and run the program, it crashes giving me:

Project1: malloc.c:2369: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.

RUN FINISHED; Aborted; core dumped; real time: 120ms; user: 0ms; system: 0ms

So I used valgrind which gave me this output:

    ==8082== Memcheck, a memory error detector
==8082== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==8082== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==8082== Command: ./out -i ab -c bc -o cd
==8082== 
==8082== Invalid write of size 1
==8082==    at 0x4C2DAEC: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8082==    by 0x400971: getInput (inputFunction.c:33)
==8082==    by 0x400730: main (main.c:11)
==8082==  Address 0x51fc043 is 0 bytes after a block of size 3 alloc'd
==8082==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8082==    by 0x400915: getInput (inputFunction.c:29)
==8082==    by 0x400730: main (main.c:11)
==8082== 

valgrind: m_mallocfree.c:268 (mk_plain_bszB): Assertion 'bszB != 0' failed.
valgrind: This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata.  If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away.  Please try that before reporting this as a bug.

==8082==    at 0x380581EF: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8082==    by 0x38058332: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8082==    by 0x3806257A: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8082==    by 0x380641F3: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8082==    by 0x3802B33C: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8082==    by 0x3802B4C2: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8082==    by 0x3809D58D: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8082==    by 0x380AC14C: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)

sched status:
  running_tid=1

Thread 1: status = VgTs_Runnable
==8082==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8082==    by 0x4009F7: getInput (inputFunction.c:41)
==8082==    by 0x400730: main (main.c:11)

I know that the problem is in the malloc but I can not find it. Any help? I am using Netbeans 7.4 on Lubuntu 13.10 with gcc 4.8.1.

Was it helpful?

Solution 2

After doing some more research I saw here that the strncpy copies n characters even if the source string is smaller than n characters. That way it was getting out of bounds of the destination string's allocated memory.

OTHER TIPS

Part of the problem may be due to the use of strnlen and strncpy. If the length of the input string given to strnlen is less than 256, it will return the actual length (a value less than 256). So the result is that malloc would allocate that many bytes. But the call to strncpy indicates the buffer is 256 bytes. And strncpy always pads up to the given length, so it is likely resulting in a memory overwrite.

Unless there is a specific reason for using strnlen, it might be simpler to use strdup, which will allocate and copy with a single call.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top