0

I am working on an object of SDL Tetris. When I ran my code, it first worked fine. But it automatically stopped displaying my text a few minutes later. I guessed there must be some problem on the memory management and I proved that I was right via Task Manager.

I look over my source code but found nothing wrong. (at least I didn't find it) Every heap object I delcared was freed and textures were destroyed. So, what can be the problem?

Here's my source code:

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

#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

SDL_Window * window;
SDL_Renderer * renderer;
SDL_Surface * text;
TTF_Font* font;

bool running = true;

#define ScreenWidth 60
#define ScreenHeight 30
#define CharWidth 14
#define CharHeight 24

char screen[ScreenHeight][ScreenWidth + 1];

SDL_Color color = {192, 192, 192};
SDL_Rect rect;

int score = 0;

char shapes[7][17];

typedef struct Block {
    int type;
    char shape[17];
    int x, y;
    int width, height;
} Block;

Block * newBlock(int type) {
    Block * block = malloc(sizeof(Block));
    return block;
}

void CheckEvents() {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        if (event.type == SDL_QUIT) {
            running = false;
        } else if (event.type == SDL_KEYDOWN) {
            switch (event.key.keysym.sym) {
                case SDLK_w:
                    ;
                    break;

                case SDLK_a:
                    ;
                    break;

                case SDLK_d:
                    ;
                    break;

                case SDLK_s:
                    ;
                    break;

                case SDLK_SPACE:
                    ;
                    break;

                default:
                    break;
            }
        }
    }

    free(&event);
}

void UpdateBoard() {
    for (int i = 0; i < ScreenHeight; ++i) {
        for (int j = 0; j < ScreenWidth; ++j) {
            screen[i][j] = ' ';
        }
    }

    for (int i = 0; i != 20; ++i) {
        screen[i + 2][1] = '#';
        screen[i + 2][1 + 10 + 1] = '#';
    }

    for (int i = 0; i != 10 + 2; ++i) {
        screen[22][i + 1] = '#';
    }

    sprintf(&(screen[0][1]), "Score: %d", score);

    for (int i = 0; i != ScreenHeight; i++) {
        for (int j = 0; j != ScreenWidth; j++) {
            if (screen[i][j] == '\0') {
                screen[i][j] = ' ';
            }
        }
    }
}

void UpdateScreen() {
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    for (int i = 0; i < ScreenHeight; ++i) {
        text = TTF_RenderText_Solid(font, screen[i], color);
        SDL_Texture * texture;
        texture = SDL_CreateTextureFromSurface(renderer, text);
        rect.x = 0;
        rect.y = i * CharHeight;
        rect.w = strlen(screen[i]) * CharWidth;
        rect.h = CharHeight;
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        free(texture);
        SDL_DestroyTexture(texture);
    }

    SDL_RenderPresent(renderer);
}

void Init() {
    SDL_Init(SDL_INIT_EVERYTHING);
    TTF_Init();

    window = SDL_CreateWindow("Tetris", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 
            ScreenWidth * CharWidth, ScreenHeight * CharHeight, 0);
    renderer = SDL_CreateRenderer(window, -1, 0);
    font = TTF_OpenFont("s8514oem.fon", 0);

    sprintf(shapes[0], "OOOO............");
    sprintf(shapes[1], "OO...OO.........");
    sprintf(shapes[2], ".OO.OO..........");
    sprintf(shapes[3], "O...OOO.........");
    sprintf(shapes[4], "..O.OOO.........");
    sprintf(shapes[5], "OO..OO..........");
    sprintf(shapes[6], "OOO..O..........");
}

int main(int argc, char ** argv) {

    Init();

    while (running) {
        CheckEvents();
        UpdateBoard();
        UpdateScreen();
        SDL_Delay(1000/16);
    }

    TTF_Quit();
    SDL_Quit();
    return 0;
}

My Makefile:

tetris:
    gcc -std=c99 -Wall -Isrc/include -Lsrc/lib -o Tetris main.c -lSDL2main -lSDL2 -lSDL2_ttf
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • 3
    valgrind......? – Mitch Wheat Jun 28 '22 at 06:59
  • Also , I commented my UpdateScreen() and UpdateBoard() function seperately and the program didn't crash. So both functions are not appropriately programmed. – Sodium Hypochlorite Jun 28 '22 at 06:59
  • 2
    Compile with all warnings and debug info, so `gcc -g -std=c99 -Wextra -Wall -Isrc/include -Lsrc/lib -o Tetris main.c -lSDL2main -lSDL2 -lSDL2_ttf`. Then use both [valgrind](https://valgrind.org/) and [GDB](https://www.sourceware.org/gdb/) – Basile Starynkevitch Jun 28 '22 at 07:00
  • does this help? [https://stackoverflow.com/questions/1473609/memory-leak-debug](https://stackoverflow.com/questions/1473609/memory-leak-debug) – SunnyMonster Jun 28 '22 at 07:01
  • 5
    `free(texture); SDL_DestroyTexture(texture);` seems insanely redundant. I cannot fathom why the latter would require a now-defunct pointer. Nor should you be `free`'ing something unless it was `malloc`'ed, `realloc`'ed, etc. I suspect the `free` is wrong, and should not be there, but I'm not an SDL guy, so take that for what it's worth. – WhozCraig Jun 28 '22 at 07:11
  • 2
    I'm quiet sure that in `UpdateScreen` you are not supposed to free the texture pointer before destroying it. Also make sure you are correctly managing whatever is created here `text = TTF_RenderText_Solid(font, screen[i], color);`. Also also, like Mitch said, use valgrind to find missing frees – Ackdari Jun 28 '22 at 07:11
  • 2
    `free(&event);` looks also totally wrong to me. You free only things that have been allocated by malloc and friends. – Jabberwocky Jun 28 '22 at 07:40
  • 1
    Just a nitpick because I saw `#define SDL_MAIN_HANDLED` in your code: https://stackoverflow.com/questions/64396979/how-do-i-use-sdl2-in-my-programs-correctly – skink Jun 28 '22 at 09:32
  • 1
    Also regarding `SDL_Delay(1000/60)`: https://gafferongames.com/post/fix_your_timestep/ – skink Jun 28 '22 at 09:33

1 Answers1

1

Several things:

  1. Don't try to free() stack-allocated variables like event:

    //free(&event);
    
  2. text needs to be freed with SDL_FreeSurface() before replacing its pointer value with a new one from TTF_RenderText_Solid():

    if(text) {
        SDL_FreeSurface(text);
    }
    text = TTF_RenderText_Solid(font, screen[i], color);
    
  3. Don't use free() on the textures returned by SDL_CreateTextureFromSurface(), only use SDL_DestroyTexture():

    texture = SDL_CreateTextureFromSurface(renderer, text);
    ...
    //free(texture);
    SDL_DestroyTexture(texture);
    
genpfault
  • 51,148
  • 11
  • 85
  • 139