Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Read Access Violation on al_destroy_bitmap()

This thread is locked; no one can reply to it. rss feed Print
Read Access Violation on al_destroy_bitmap()
lCoopsl
Member #16,804
February 2018

I have a fairly small project in the making right now and I'm currently trying to implement graphic/bitmap handling. I have a class set up which contains an ALLEGRO_BITMAP variable along with other variables.

The class has a destructor which calls al_destroy_bitmap(). However, this function is causing the program to crash upon a 'Read Access Violation' within the allegro function.

I get confused where callstack tells me it reaches all the way into _al_set_bitmap_shader_field() inside of the al_destroy_bitmap() function. To be even more precise, the error returns "bmp was 'real memory address'" which tells me perhaps the BITMAP wasn't allocated properly or that it somehow now floats in unreachable memory space, or even the pointer isn't pointing to the_ALLEGRO_BITMAP at the time of the error.

looking into allegro's source code, it crashes on line 418 of shader.c which contains

#SelectExpand
414void _al_set_bitmap_shader_field(ALLEGRO_BITMAP *bmp, ALLEGRO_SHADER *shader) 415{ 416 ASSERT(bmp); 417 418 if (bmp->shader != shader) { // <- LINE 418 419 if (bmp->shader) { 420 _al_unregister_shader_bitmap(bmp->shader, bmp); 421 } 422 bmp->shader = shader; 423 if (bmp->shader) { 424 _al_register_shader_bitmap(bmp->shader, bmp); 425 } 426 } 427}

debugging and trying to reveal bmp->shader (in the case of my script 'bmap->shader') returns an error of "incomplete class type".

I use several header files:

image.h, which contains the class declaration.

#SelectExpand
1#pragma once 2#ifndef ALLEGRO 3#define ALLEGRO 4#include <allegro5/allegro.h> 5#include <iostream> 6#endif // !ALLEGRO 7 8#ifndef IMAGE_H 9#define IMAGE_H 10#include <allegro5/allegro_image.h> 11#include <allegro5/allegro_primitives.h> 12 13// IMAGE HANDLING 14 15class Image { 16public: 17 int x, y, width, height, scale; 18 bool mirrored; 19 ALLEGRO_BITMAP *bmap; 20 char* path; 21 22 Image(void); 23 Image(int, int, int, int, int, bool); 24 ~Image(void); 25 void setImage(char*); 26 void draw(void); 27 void drawTint(ALLEGRO_COLOR); 28}; 29 30#endif // !IMAGE_H

image.cpp, which contains the class implementation along with some class constructors (for global use).

#SelectExpand
1#pragma once 2#ifndef ALLEGRO 3#define ALLEGRO 4#include <allegro5/allegro.h> 5#include <iostream> 6#endif // !ALLEGRO 7 8#include "image.h" 9 10Image background(200, 200, 200, 200, 2, false); 11Image soldierA(100, 100, 32, 24, 4, false); 12Image soldierB(100, 100, 32, 24, 2, false); 13 14Image::Image(void) { 15 x = y = 0; 16 width = height = 0; 17 scale = 1; 18 mirrored = false; 19} 20Image::Image(int xA, int yA, int w, int h, int scaleA, bool mirror) { 21 x = xA; 22 y = yA; 23 width = w; 24 height = h; 25 scale = scaleA; 26 mirrored = mirror; 27} 28Image::~Image(void) { 29 al_destroy_bitmap(bmap); // <- CULPRIT FUNCTION 30} 31 32void Image::setImage(char*source) { 33 bmap = al_load_bitmap(source); 34} 35void Image::draw() { 36 if (bmap != NULL) 37 al_draw_scaled_bitmap(bmap, 0, 0, width, height, x - (width / 2) * scale, y - (height / 2) * scale, width * scale, height * scale, mirrored ? ALLEGRO_FLIP_HORIZONTAL : 0); 38} 39void Image::drawTint(ALLEGRO_COLOR color) { 40 if (bmap != NULL) 41 al_draw_tinted_scaled_bitmap(bmap, color, 0, 0, width, height, x - (width / 2) * scale, y - (height / 2) * scale, width * scale, height * scale, mirrored ? ALLEGRO_FLIP_HORIZONTAL : 0); 42}

imageLib.h, which contains a dictionary of the class objects I use in main.cpp along with initialization functions.

#SelectExpand
1#pragma once 2#include "image.h" 3 4extern Image background; 5extern Image soldierA; 6extern Image soldierB; 7 8bool loadImages() { 9 background.setImage("Graphics/StatScreen.png"); 10 soldierA.setImage("Graphics/GreatswordGuy.png"); 11 soldierB.setImage("Graphics/GreatswordGuy.png"); 12 return true; 13} 14 15void destroyImages() { 16 background.~Image(); 17 soldierA.~Image(); 18 soldierB.~Image(); 19}

and finally main.cpp which contains the main source code and utilizes the header files.

#SelectExpand
1#define ALLEGRO 2#include <allegro5/allegro.h> 3#include <iostream> 4 5//#include "image.h" 6#include "imageLib.h" 7 8using namespace std; 9 10const int WINDOW_WIDTH = 400, WINDOW_HEIGHT = 400; 11const float FPS = 60; 12 13float scale = 4.0; 14 15ALLEGRO_DISPLAY* initDisplay() { 16 ALLEGRO_DISPLAY *display = NULL; 17 //display = al_create_display(w, h); 18 return display; 19} 20 21int main(int argc, char **argv) { 22 23 if (!al_init()) { 24 cout << "failed to initialize allegro!\n"; 25 return -1; 26 } 27 cout << "ALLEGRO INITIALIZED...\n"; 28 if (!al_install_keyboard()) { 29 cout << "failed to initialize the keyboard!\n"; 30 return -1; 31 } 32 if (!al_install_mouse()) { 33 cout << "failed to initialize the mouse!\n"; 34 return -1; 35 } 36 //if (!al_init_font_addon()) { 37 // cout << "failed to initialize font add-on!\n"; 38 //} 39 40 al_init_image_addon(); 41 al_init_primitives_addon(); 42 //al_init_font_addon(); 43 44 ALLEGRO_DISPLAY *display = initDisplay(); 45 //ALLEGRO_FONT *font = al_create_builtin_font(); 46 47 display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT); 48 49 loadImages(); 50 51/* 52 53simulation code snipped 54 55*/ 56 57 destroyImages(); 58 59 al_set_target_bitmap(NULL); 60 61 al_destroy_display(display); 62 63 return 0; 64}

Thanks in advance.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Never call the destructor yourself. Only through delete.

What's happening is that the destructor runs twice, once when you call destroy images, and again after main exits and the global destructors run.

Solutions;

1. Make your Image objects local to main.

2. Make your Image objects pointers and use new and delete.

3. Move your destruction code into a separate function you call from your destructor and call it yourself if the objects are global, making sure to only free / delete resources once.

Go to: