c - realloc fails when running .out.exe via Makefile, but works when run manually - Stack Overflow

admin2025-04-19  6

I'm having an issue where, when I run my already compiled program ./main.exe (gcc main.c -o main.exe) through a Makefile, a realloc call fails when the size goes over 40 bytes. However, if I run ./main.exe manually, everything works as expected.

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

typedef struct
{
    char **array;
    int size;
} stringList;

void add_string(stringList *list, char *string)
{
    printf("Arr size: %zu. ", ((list->size) + 1) * sizeof(char *));
    char **newAddress = realloc(list->array, ((list->size) + 1) * sizeof(char *));
    if (newAddress != NULL)
    {
        char *newString = malloc((strlen(string) + 1) * sizeof(char));
        if (newString != NULL)
        {
            strcpy(newString, string);
            list->array = newAddress;
            list->array[list->size] = newString;
            list->size++;
            printf("Fine. ");
        }
        else
        {
            printf("Allocating new string failed. ");
        }
    }
    else
    {
        printf("Allocating new array failed. ");
    }
}

int main(int argc, char *argv[])
{
    stringList list = { NULL, 0 };
    if (argc != 3)
    {
        argv[1] = malloc(3 * sizeof(char)); argv[1] = "in";
        argv[2] = malloc(3 * sizeof(char)); argv[2] = "out";
    }
    FILE *input = fopen(argv[1], "r");
    FILE *output = fopen(argv[2], "w");
    // I found that the line above may cause the problem (but I left it because I will use it)

    char buffer[256] = {0};
    while (fscanf(input, "%s", buffer) != EOF)
    {
        add_string(&list, buffer);
    }

    fclose(input);
    fclose(output);
    return 0;
}

I used this simple "in" file for test:

1 2 3 4 5 6 7 8 9 10 11 12 13

So here, if I manually start ./main.exe, adding goes just fine

PS C:\Users\Ivan\Desktop\maketest> ./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine.
PS C:\Users\Ivan\Desktop\maketest> ./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine.

But running makefile make run (this is the entire file below)

.PHONY: run

run:
    ./main.exe

It has 50% chance either to work correctly or give errors as the size exceeds 40 till the end.

PS C:\Users\Ivan\Desktop\maketest> make run
./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Allocating new array failed. Arr size: 44. Allocating new array failed. Arr size: 44. Allocating new array failed.
PS C:\Users\Ivan\Desktop\maketest> make run
./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine.

I appreciate any explanation! I expect to start the exe via makefile normaly and understand my mistake.

I'm having an issue where, when I run my already compiled program ./main.exe (gcc main.c -o main.exe) through a Makefile, a realloc call fails when the size goes over 40 bytes. However, if I run ./main.exe manually, everything works as expected.

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

typedef struct
{
    char **array;
    int size;
} stringList;

void add_string(stringList *list, char *string)
{
    printf("Arr size: %zu. ", ((list->size) + 1) * sizeof(char *));
    char **newAddress = realloc(list->array, ((list->size) + 1) * sizeof(char *));
    if (newAddress != NULL)
    {
        char *newString = malloc((strlen(string) + 1) * sizeof(char));
        if (newString != NULL)
        {
            strcpy(newString, string);
            list->array = newAddress;
            list->array[list->size] = newString;
            list->size++;
            printf("Fine. ");
        }
        else
        {
            printf("Allocating new string failed. ");
        }
    }
    else
    {
        printf("Allocating new array failed. ");
    }
}

int main(int argc, char *argv[])
{
    stringList list = { NULL, 0 };
    if (argc != 3)
    {
        argv[1] = malloc(3 * sizeof(char)); argv[1] = "in";
        argv[2] = malloc(3 * sizeof(char)); argv[2] = "out";
    }
    FILE *input = fopen(argv[1], "r");
    FILE *output = fopen(argv[2], "w");
    // I found that the line above may cause the problem (but I left it because I will use it)

    char buffer[256] = {0};
    while (fscanf(input, "%s", buffer) != EOF)
    {
        add_string(&list, buffer);
    }

    fclose(input);
    fclose(output);
    return 0;
}

I used this simple "in" file for test:

1 2 3 4 5 6 7 8 9 10 11 12 13

So here, if I manually start ./main.exe, adding goes just fine

PS C:\Users\Ivan\Desktop\maketest> ./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine.
PS C:\Users\Ivan\Desktop\maketest> ./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine.

But running makefile make run (this is the entire file below)

.PHONY: run

run:
    ./main.exe

It has 50% chance either to work correctly or give errors as the size exceeds 40 till the end.

PS C:\Users\Ivan\Desktop\maketest> make run
./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Allocating new array failed. Arr size: 44. Allocating new array failed. Arr size: 44. Allocating new array failed.
PS C:\Users\Ivan\Desktop\maketest> make run
./main.exe
Arr size: 4. Fine. Arr size: 8. Fine. Arr size: 12. Fine. Arr size: 16. Fine. Arr size: 20. Fine. Arr size: 24. Fine. Arr size: 28. Fine. Arr size: 32. Fine. 
Arr size: 36. Fine. Arr size: 40. Fine. Arr size: 44. Fine. Arr size: 48. Fine. Arr size: 52. Fine.

I appreciate any explanation! I expect to start the exe via makefile normaly and understand my mistake.

Share Improve this question edited Jan 28 at 21:06 omon asked Jan 28 at 12:45 omonomon 11 bronze badge 11
  • 2 Can you please add the #includes and the whole makefile to reproduce the problem? How are you compiling it? How is the makefile compiling it? – mch Commented Jan 28 at 12:54
  • 5 Was list->array originally set by allocation, or was it explicitly initialized to NULL? A Minimal Reproducible Example would help. Erratic behaviour can be a symptom of undefined behaviour, so perhaps it was never explictly set, and only happened to be NULL in the successful one. – Weather Vane Commented Jan 28 at 12:57
  • 1 unrelated to your problem, but both %d in the printf should be %zu, because the strlen and the sizeof evaluates to the type size_t. – mch Commented Jan 28 at 13:48
  • 1 Please add text output as formatted text into your question instead of showing a picture of it. – Gerhardh Commented Jan 28 at 14:22
  • 2 I do not find it credible that running the command indirectly via make vs running the same command directly from the command line is what makes a difference here. Possibly the particular makefile used contains additional code, not shown, that that causes a meaningfully different environment to be provided in the run-via-make case, but then the difference would be a function of the makefile, not of make itself. – John Bollinger Commented Jan 28 at 16:53
 |  Show 6 more comments

1 Answer 1

Reset to default 1

I think commenter John Bollinger is on the right track, but it's maybe worse than he suggests. Assigning to argv when it may not be allocated might be your problem. It's certainly a bug in any case. This:

        argv[1] = malloc(3 * sizeof(char)); argv[1] = "in";
        argv[2] = malloc(3 * sizeof(char)); argv[2] = "out";

is certainly bogus. Not only are you assigning memory to locations in argv that are not allocated unless argc is 3 or more, you are allocating memory with malloc() that is lost (orphaned) when you overwrite the pointers with the addresses of the strings "in" and "out".

I would suggest trying something like:

    char *inf = "in", *outf = "out";
    if (argc == 3) {
        inf = argv[1];
        outf = argv[2];
    }
    FILE *input = fopen(inf, "r");
    FILE *output = fopen(outf, "w");

And also you may want to free all the memory at the end:

    for (int i=0;i<list.size;i++)
        free(list.array[i]);
    free(list.array);

I think it's unnecessary to free allocated memory at the end of a program generally speaking, but I ran the code under ASAN and it complains if I don't.

And BTW * sizeof(char) is unneeded; it's always 1.

转载请注明原文地址:http://anycun.com/QandA/1745022763a90350.html