0

I am writing a simple program that at first checks a file for the number of structures present and allocates memory accordingly, then allows the user to insert new registries and allocates memory for those as well. Before program is terminated, all the data is saved to a binary file. I am able to insert up to 8 "servidor", but no more. When debugging, I found that after 8 entries, the program fails to realloc for a 9th, which indicates memory problems.

Call Stack

ntdll.dll!ntdll!RtlRaiseException (Unknown Source:0)
ntdll.dll!ntdll!RtlIsZeroMemory (Unknown Source:0)
ntdll.dll!ntdll!RtlIsZeroMemory (Unknown Source:0)
ntdll.dll!ntdll!.misaligned_access (Unknown Source:0)
ntdll.dll!ntdll!.misaligned_access (Unknown Source:0)
ntdll.dll!ntdll!.misaligned_access (Unknown Source:0)
ntdll.dll!ntdll!RtlReAllocateHeap (Unknown Source:0)
ntdll.dll!ntdll!RtlReAllocateHeap (Unknown Source:0)
AcLayers.dll!NotifyShims (Unknown Source:0)
msvcrt.dll!realloc (Unknown Source:0)
main() (c:\Users\tiago\Desktop\c.c:145)

Steps to reproduce

  1. Compile
  2. Run
  3. Insert many registries by typing 1 and typing a name.
  4. Program should fail at about 8 insertions, reverting file back to previous saved state, or 0.

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

typedef struct Servidor
{
    bool ocupado;
    int codigo;
    char nome[256];
} servidor;

int escrever_arquivo(void * _struct, size_t tam_struct, int tamanho)
{
    FILE *fptr = fopen("data.bin", "w");
    if(fptr == NULL)
    {
        return 1;
    }

    fwrite(_struct, tam_struct * tamanho, 1, fptr);

    fclose(fptr);
}

int ler_arquivo(void * _struct, size_t tam_struct, int tamanho)
{
    FILE *fptr = fopen("data.bin", "r");
    if(fptr == NULL)
    {
        return 1;
    }

    fread(_struct, tam_struct * tamanho, 1, fptr);

    fclose(fptr);
}

int busca_tamanho()
{
    FILE *fptr = fopen("data.bin", "a");
    if(fptr == NULL)
    {
        printf("Erro na abertura do arquivo!\n");
        exit(1);
    }

    fseek(fptr, 0L, SEEK_END);
    int tamanho = ftell(fptr);

    fclose(fptr);

    return tamanho / sizeof(servidor);
}

int busca_livre(servidor * grupo, int tamanho)
{
    for(int i = 0; i < tamanho; i++)
    {
        if(grupo[i].ocupado != true)
        {
            return i;
        }
    }
}

void inserir_servidor(servidor * grupo, int tamanho)
{
    if(!tamanho)
    {
        grupo[0].ocupado = true;

        grupo[0].codigo = 0;

        printf("Nome: ");
        fgets(grupo[0].nome, sizeof(grupo[0].nome), stdin);
        fflush(stdin);
    }
    else
    {
        int pos = busca_livre(grupo, tamanho);

        grupo[pos].ocupado = true;

        grupo[pos].codigo = pos;

        printf("Nome: ");
        fgets(grupo[pos].nome, sizeof(grupo[pos].nome), stdin);
        fflush(stdin);
    }
}

void imprimir_servidor(servidor * grupo, int tamanho)
{
    for(int i = 0; i < tamanho; i++)
    {
        printf("%s %d\n\n", grupo[i].nome, grupo[i].codigo);
    }
}

int main()
{
    servidor * grupo;

    int tamanho = busca_tamanho();
    int memoria = tamanho * sizeof(servidor);

    if(tamanho)
    {
        grupo = malloc(memoria);
        ler_arquivo(grupo, sizeof(servidor), tamanho);
    }

    char input;

    printf("memoria inicial: %d B , tamanho: %d\n\n", memoria, tamanho);

    do
    {
        printf("1. Inserir servidor\n");
        printf("2. Listar servidores\n");
        printf("0. Sair do programa\n\n");
        printf("> ");

        scanf("%c", &input);
        fflush(stdin);

        switch(input)
        {
            case '0':
                escrever_arquivo(grupo, sizeof(servidor), tamanho);
                free(grupo);
                printf("Saindo do programa\n");
                return 0;
            case '1':

                if(!tamanho)
                {
                    grupo = malloc(sizeof(servidor));
                    memoria += sizeof(servidor);

                    tamanho++;
                    inserir_servidor(grupo, tamanho);
                }
                else
                {
                    realloc(grupo, memoria + sizeof(servidor));
                    memoria += sizeof(servidor);

                    tamanho++;
                    inserir_servidor(grupo, tamanho);
                }
                printf("memoria em uso: %d B , tamanho: %d\n\n", memoria, tamanho);
                break;

            case '2':
                imprimir_servidor(grupo, tamanho);
                break;
            default:
                printf("Inexistente\n");
                break;
        }

    } while(input != '0');

    return 0;
}
  • Possibly not related but `scanf("%c", &input);` should be `scanf(" %c", &input);` with a space before the format string to skip leading whitespace, like the leftover newline, and `fflush(stdin);` is undefined behavior. [scanf() leaves the newline character in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-newline-character-in-the-buffer) and [Using fflush(stdin)](https://stackoverflow.com/questions/2979209/using-fflushstdin) for more details. – Retired Ninja May 23 '22 at 02:20
  • 1
    `realloc(grupo, memoria + sizeof(servidor));`, if successful, invalidates the old pointer value, and discards the new one. – Oka May 23 '22 at 02:25
  • 1
    `realloc(grupo, memoria + sizeof(servidor));` ignores the return value of `realloc`. If the existing block can't be extended and it returns a pointer to a new block you don't capture it and continue to use a freed block of the previous size. – Retired Ninja May 23 '22 at 02:25
  • @RetiredNinja That's it! It was just my fundamentally flawed understanding of realloc. Back to learning. Do you have any recommendations based on my code? – jamescodec May 23 '22 at 02:33
  • First comment covers two that might be relevant. The only other possible issue you could have is that you're not opening the files in binary mode, especially since you're on Windows where it can lead to very hard to figure out issues. – Retired Ninja May 23 '22 at 02:38
  • Also, check the return value of any library function that can fail (`fread`, `fwrite`, `fseek`, `fgets`, etc.). – Oka May 23 '22 at 02:50

0 Answers0