Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » VS 2017 Release & Allegro bitmaps

This thread is locked; no one can reply to it. rss feed Print
VS 2017 Release & Allegro bitmaps
lCoopsl
Member #16,804
February 2018

I'm having a strange problem with Visual Studio 2k17 and I'm hoping to find some insight on the matter here.

On Debug it compiles and builds fine. However, on Release it runs into some problems.

Here's a simplified version of my program, contained in an header implementation file.

#SelectExpand
1const int MAX_BITMAPS = 256; 2 3ALLEGRO_BITMAPS *bitmap_STORAGE[MAX_BITMAPS]; 4 5enum BITMAPS { 6 SPRITE_A = 1, 7 SPRITE_B, 8 SPRITE_C = 5, 9} 10 11void loadBitmaps() { 12 for (int i = 0; i < MAX_BITMAPS; i++) 13 bitmaps_STORAGE[i] = nullptr; 14 15 ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH); 16 al_append_path_component(path, "resources"); 17 al_change_directory(al_path_cstr(path, '/')); 18 al_destroy_path(path); 19 20 bitmaps_STORAGE[SPRITE_A] = al_load_bitmap("sprite_A.png"); 21 bitmaps_STORAGE[SPRITE_B] = al_load_bitmap("sprite_B.png"); 22 bitmaps_STORAGE[SPRITE_C] = al_load_bitmap("sprite_C.png"); 23} 24 25void destroyBitmaps() { 26 for (int i = 0; i < MAX_BITMAPS; i++) { 27 al_destroy_bitmap(bitmaps_STORAGE[i]); 28 } 29}

Now, I have two instances of issues here.

The first instance is setting SPRITE_A's enum to 0. When I do this, al_load_bitmap(...) crashes the program and gives a read access violation.

The second instance is looking at the code above, but this time al_destroy_bitmap(...), at the first iteration of the for loop (index 0), crashes the program, giving another read access violation.

These are the only allegro calls for creating and deleting, nothing else affects variables directly.

Am I experiencing heap corruption or are the allegro functions failing on my part?

Edgar Reynaldo
Member #8,592
May 2007
avatar

You need to learn how enums and arrays work. An array is zero-indexed. That means the first element is at index 0. That means you want your enum to start at 0. Your array is uninitialized. It holds random values until you set them to something sensible like 0. This is why your destruction for loop crashes, because it is trying to destroy nonsense memory addresses.

enum SPRITE_INDEX {
   SPRITE_A = 0,
   SPRITE_B = 1,
   SPRITE_C = 2,
   NUM_SPRITES = 3
};

ALLEGRO_BITMAP* sprites[NUM_SPRITES] = {0};

lCoopsl
Member #16,804
February 2018

Is al_destroy_bitmap() not capable of deleting a nullptr value?

I figured initializing the entire array to nullptr would be trivial, but keep it from holding onto garbage before attempting to delete those pointers.

Edgar Reynaldo
Member #8,592
May 2007
avatar

The values in the array are not null. They're undefined. You have to initialize them to zero. Whether al_destroy_bitmap handles null values is not the point.

lCoopsl
Member #16,804
February 2018

I'm still running into the issue of al_load_bitmap(...) crashing when SPRITE_A is set to 0.

When I set SPRITE_A to anything above 1, then it no longer crashes and the destruction crash happens.

Initializing sprite_STORAGE[] with '0' has had no effect.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Actually, you did initialize the bitmap_storage array to null. Nevermind that, I didn't see it. However, al_load_bitmap should never crash, only return NULL on failure.

Post an actual example program that crashes and fails and we can see what's wrong.

lCoopsl
Member #16,804
February 2018

#SelectExpand
1const int MAX_BITMAPS = 256; 2 3ALLEGRO_BITMAP* bitmaps_SPRITES[MAX_BITMAPS] = { 0 }; 4 5enum BITMAPS { 6 //SPLASHES 7 HOME_SPLASH = 2, 8 HOME_PROP_A, 9 STATS_SPLASH, 10 WAR_SPLASH, 11 TITLE_SPLASH, 12// CONFLICT_SPLASH, 13// SKIRMISH_SPLASH, 14 15 FIGHT_HEADER, 16 FIGHT_SPLASH_A, 17 18 //MENUS 19 PAUSE_MENU, 20 LOADOUT_MENU, 21 ABILITIES_MENU, 22 23 ITEM_NOTICE, 24 VICTORY_MENU, 25 DEFEAT_MENU, 26 27 28 //BUTTONS 29 DEFAULT_BUTTON = 20, 30 OPTIONA_BUTTON, 31 OPTIONB_BUTTON, 32 EQUIP_BUTTON, 33 34 FIGHT_START_BUTTON, 35 36 ABILITY_BUTTONS, 37 ATTACK_BUTTON, 38 39 //CLOTHES 40 SWORD_GUY = 50, 41 SWORD_GUY_ROUND, 42 SWORD_GUY_KITE, 43 SWORD_GUY_TOWER, 44 //SWORD_GUY_FULL, 45 46 SPEAR_GUY, 47 SPEAR_GUY_ROUND, 48 SPEAR_GUY_KITE, 49 SPEAR_GUY_TOWER, 50 //SPEAR_GUY_FULL, 51 52 GREAT_GUY, 53 GREAT_GUY_ROUND, 54 GREAT_GUY_KITE, 55 GREAT_GUY_TOWER, 56 //GREAT_GUY_FULL, 57 58 KNIGHT_GUY, 59 60 //MISC 61 62 TOOLTIP = 70, 63 RANK_LABEL, 64 65 SPLATS, 66 HP_BLIP, 67 COMPARE, 68 LEVEL_STAT, 69 70 WEAPON_SLOT, 71 ARMOR_SLOT, 72 SHIELD_SLOT, 73 TRINKET_SLOT, 74 75 SPEED_BAR, 76 77 ANIMATION_TEST, 78 ANIMATION_TEST2, 79 80 CHLOE, 81 82 enumTypeEnd = 255 83}; 84 85ALLEGRO_BITMAP *getBitmap(const char *Filename) { 86 ALLEGRO_BITMAP *bitmap = al_load_bitmap(Filename); 87 if (bitmap == NULL) { 88 std::cout << "ERROR LOADING BITMAP: " << Filename << std::endl; 89 bitmap = al_load_bitmap("null.png"); 90 } 91 return bitmap; 92} 93 94void loadBitmaps() { 95 //for (int i = 0; i < MAX_BITMAPS; i++) 96 // bitmaps_SPRITES[i] = nullptr; 97 98 ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH); 99 al_append_path_component(path, "resources"); 100 al_change_directory(al_path_cstr(path, '/')); 101 al_destroy_path(path); 102 103 bitmaps_SPRITES[HOME_SPLASH] = getBitmap("backgrounds/homeSplash.png"); 104 bitmaps_SPRITES[HOME_PROP_A] = getBitmap("backgrounds/homeSheet.png"); 105 106 bitmaps_SPRITES[STATS_SPLASH] = getBitmap("backgrounds/StatScreen.png"); 107 bitmaps_SPRITES[WAR_SPLASH] = getBitmap("backgrounds/warView.png"); 108 bitmaps_SPRITES[TITLE_SPLASH] = getBitmap("titleSheet.png"); 109 110 bitmaps_SPRITES[FIGHT_HEADER] = getBitmap("backgrounds/battleHeader.png"); 111 bitmaps_SPRITES[FIGHT_SPLASH_A] = getBitmap("backgrounds/fightSplash00.png"); 112 113 bitmaps_SPRITES[PAUSE_MENU] = getBitmap("backgrounds/pauseMenu.png"); 114 bitmaps_SPRITES[LOADOUT_MENU] = getBitmap("backgrounds/loadoutMenu.png"); 115 bitmaps_SPRITES[ABILITIES_MENU] = getBitmap("backgrounds/abilitiesMenu.png"); 116 117 bitmaps_SPRITES[ITEM_NOTICE] = getBitmap("backgrounds/itemNotice.png"); 118 bitmaps_SPRITES[VICTORY_MENU] = getBitmap("backgrounds/victoryMenu.png"); 119 bitmaps_SPRITES[DEFEAT_MENU] = getBitmap("backgrounds/defeatMenu.png"); 120 121 bitmaps_SPRITES[DEFAULT_BUTTON] = getBitmap("defaultButton.png"); 122 bitmaps_SPRITES[OPTIONA_BUTTON] = getBitmap("optionButtonA.png"); 123 bitmaps_SPRITES[OPTIONB_BUTTON] = getBitmap("optionButtonB.png"); 124 bitmaps_SPRITES[EQUIP_BUTTON] = getBitmap("equipButton.png"); 125 126 bitmaps_SPRITES[FIGHT_START_BUTTON] = getBitmap("fightStart.png"); 127 128 bitmaps_SPRITES[ABILITY_BUTTONS] = getBitmap("abilityButtons.png"); 129 bitmaps_SPRITES[ATTACK_BUTTON] = getBitmap("attackButton.png"); 130 131 bitmaps_SPRITES[SWORD_GUY] = getBitmap("clothes/swordGuySheet.png"); 132 bitmaps_SPRITES[SWORD_GUY_ROUND] = getBitmap("clothes/swordGuyRoundSheet.png"); 133 bitmaps_SPRITES[SWORD_GUY_KITE] = getBitmap("clothes/swordGuyKiteSheet.png"); 134 bitmaps_SPRITES[SWORD_GUY_TOWER] = getBitmap("clothes/swordGuyTowerSheet.png"); 135 136 bitmaps_SPRITES[SPEAR_GUY] = getBitmap("clothes/spearGuySheet.png"); 137 bitmaps_SPRITES[SPEAR_GUY_ROUND] = getBitmap("clothes/spearGuyRoundSheet.png"); 138 bitmaps_SPRITES[SPEAR_GUY_KITE] = getBitmap("clothes/spearGuyKiteSheet.png"); 139 bitmaps_SPRITES[SPEAR_GUY_TOWER] = getBitmap("clothes/spearGuyTowerSheet.png"); 140 141 bitmaps_SPRITES[GREAT_GUY] = getBitmap("clothes/greatGuySheet.png"); 142 bitmaps_SPRITES[GREAT_GUY_ROUND] = getBitmap("clothes/greatGuyRoundSheet.png"); 143 bitmaps_SPRITES[GREAT_GUY_KITE] = getBitmap("clothes/greatGuyKiteSheet.png"); 144 bitmaps_SPRITES[GREAT_GUY_TOWER] = getBitmap("clothes/greatGuyTowerSheet.png"); 145 146 bitmaps_SPRITES[KNIGHT_GUY] = getBitmap("clothes/knightGuySheet.png"); 147 148 bitmaps_SPRITES[TOOLTIP] = getBitmap("tooltip.png"); 149 bitmaps_SPRITES[RANK_LABEL] = getBitmap("rankSheet.png"); 150 151 bitmaps_SPRITES[SPLATS] = getBitmap("splatSheet.png"); 152 bitmaps_SPRITES[HP_BLIP] = getBitmap("hpBlipSheet.png"); 153 bitmaps_SPRITES[COMPARE] = getBitmap("compareSheet.png"); 154 bitmaps_SPRITES[LEVEL_STAT] = getBitmap("lvlButton.png"); 155 156 bitmaps_SPRITES[WEAPON_SLOT] = getBitmap("weapTab.png"); 157 bitmaps_SPRITES[ARMOR_SLOT] = getBitmap("armoTab.png"); 158 bitmaps_SPRITES[SHIELD_SLOT] = getBitmap("shieTab.png"); 159 bitmaps_SPRITES[TRINKET_SLOT] = getBitmap("trinTab.png"); 160 161 bitmaps_SPRITES[SPEED_BAR] = getBitmap("speedBar.png"); 162 163 bitmaps_SPRITES[ANIMATION_TEST] = getBitmap("test/testSheet.png"); 164 165 bitmaps_SPRITES[ANIMATION_TEST2] = getBitmap("clothes/greatGuySheet.png"); 166 167 bitmaps_SPRITES[CHLOE] = getBitmap("test/chloe.png"); 168} 169 170void destroyBitmaps() { 171 for (int i = 0; i < 0; i++) { 172 std::cout << i << "\t" << bitmaps_SPRITES[i] << std::endl; // CRASHES AT ITERATION 0. 173 al_destroy_bitmap(bitmaps_SPRITES[i]); 174 } 175}

EDIT: Making 'i' start at 2 (or whatever the first bitmap index is, above 1) instead of 0 in the destruction function seems to fixed the destruction crash.

Still doesn't answer the question of why it crashes when loading at index 0.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Something else is going on. Neither one of those functions should be crashing. Have you compiled in debug mode and looked at allegro.log?

lCoopsl
Member #16,804
February 2018

I've managed to get past the al_load_bitmap() function error. Small mistake with directories.

However, another issue has showed up. This time with al_clone_bitmap(), which attempts to clone a bitmap from the array shown. Crashes with a read access violation error upon attempting to clone the first indexed bitmap, even though al_load_bitmap did not return NULL.

Again, the strange thing about this is this only appears to be a problem if I assign the first indexed bitmap below an index of 1. If I set the first loaded bitmap's index above 1, then everything works as intended.

I'm not entirely sure how to read the allegro log file, should I include it?

EDIT: Further testing shows that this error is actually inconsistent. Sometimes it builds, sometimes it doesn't. But when it does build, the first indexed bitmap didn't properly load, and shows as an empty bitmap (No image). Any others loaded afterward are fine though.

When I try to exit the program the destruction error happens again, with the first indexed bitmap.

EDIT 2:

Some debug info...

Debug Build:
https://i.gyazo.com/thumb/1200/97152037910034f5c72c325787967a43-png.jpg

Release Build: WITH FIRST INDEX SET TO 1...
https://i.gyazo.com/thumb/1200/e3370b2db7aa1c58c24a29599a040f59-png.jpg

Release Build: WITH FIRST INDEX SET TO 2...
https://i.gyazo.com/thumb/1200/956ed6fe576af79be764d6c80077bcbb-png.jpg

Something is affecting the first two indexes of this array in Release build.

Edgar Reynaldo
Member #8,592
May 2007
avatar

This shouldn't even run.

lCoopsl said:

void destroyBitmaps() {
for (int i = 0; i < 0; i++) {
std::cout << i << "\t" << bitmaps_SPRITES[i] << std::endl; // CRASHES AT ITERATION 0. al_destroy_bitmap(bitmaps_SPRITES[i]); } }

Try to make a minimal example that does the same thing. I don't have all your resources so I can't test your example.

lCoopsl
Member #16,804
February 2018

Not sure how that got in but thats a typo, its iterating over the entire array. 0 should be MAX_BITMAPS.

However I've solved the issue somehow.

I was loading bitmaps in another file and for some reason, al_load_bitmap(...) was corrupting the pointers in the bitmap storage array in this file indirectly. Still strange since even though I was loading much more than just 2 bitmaps in the separate file, it only affected the first two indexes of the bitmap storage array in this file. And that this was only happening in the Release build.

Loading the bitmaps in the separate file before the ones in this one has fixed my issue on all accounts. The only cause I can come up with is my messy ordering of header files.

EDIT:

Here is the separate file. The original file includes this one.

#SelectExpand
1#include <allegro5/allegro_font.h> 2#include <allegro5/allegro_ttf.h> 3 4ALLEGRO_FONT *Fonts[Total_Fonts]; 5 6enum FONTS { 7 FONT_STANDARD_SMALL, 8 FONT_STANDARD_MEDIUM, 9 FONT_STANDARD_LARGE, 10 FONT_STANDARD_EXTRA, 11 FONT_WARM, 12 FONT_WARM_LARGE, 13 FONT_COLD, 14 FONT_COLD_LARGE, 15 16 Total_Fonts, 17}; 18 19ALLEGRO_FONT* getBitmapFont(const char* File) { 20 int ranges[2] = { 48, 57 }; 21 ALLEGRO_BITMAP *bitmap = al_load_bitmap(File); 22 ALLEGRO_FONT *font = al_grab_font_from_bitmap(bitmap, 1, ranges); 23 al_destroy_bitmap(bitmap); 24 25 return font; 26} 27 28void loadFonts() { 29 ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH); 30 al_append_path_component(path, "resources/fonts"); 31 al_change_directory(al_path_cstr(path, '/')); 32 al_destroy_path(path); 33 34 Fonts[FONT_STANDARD_SMALL] = al_load_ttf_font("candlebright.ttf", 10, NULL); 35 Fonts[FONT_STANDARD_MEDIUM] = al_load_ttf_font("candlebright.ttf", 12, NULL); 36 Fonts[FONT_STANDARD_LARGE] = al_load_ttf_font("candlebright.ttf", 15, NULL); 37 Fonts[FONT_STANDARD_EXTRA] = al_load_ttf_font("candlebright.ttf", 20, NULL); 38 39 Fonts[FONT_WARM] = getBitmapFont("fontWarm.png"); 40 Fonts[FONT_WARM_LARGE] = getBitmapFont("fontWarmBig.png"); 41 Fonts[FONT_COLD] = getBitmapFont("fontCold.png"); 42 Fonts[FONT_COLD_LARGE] = getBitmapFont("fontColdBig.png"); 43} 44 45void destroyFonts() { 46 for (int i = 0; i < Total_Fonts; i++) { 47 al_destroy_font(Fonts[i]); 48 } 49}

Edgar Reynaldo
Member #8,592
May 2007
avatar

One thing. You're declaring Fonts before Total_Fonts is named in the enum.

Another, you're not declaring the Fonts array as extern and defining it inside another module. That could give you problems.

Go to: