Question About 'destroy_bitmap'
Damian Grove

I understand that if you try to use free() on a location that has 'already' been freed, this can lead to memory leaks. However, I'm curious to know if the same applies to Allegro's destroy_bitmap() function. Is it safe for my program to run that function on a location that is not allocated?

Peter Wang

No, it's not safe.

The problem with double free() is not with memory leaking, but crashes.

Birdeeoh

Best case in a well-behaving environment double-freeing doesn't cause memory leaks - it's FATAL.
Worst case in a misbehaving environment, double-freeing is "undefined behavior", which can be even worse than fatal.

destroy_bitmap() involves a free() operation, so, you do the math ;)

HoHo

I think calling free/destroy_bitmap on null pointers is safe. That means, every time you free some memory or delete a bitmap, set it's pointer to null.

Neil Walker

if the pointer is null then destroy_bitmap returns without doing anything. this then means if you have an unitialised pointer variable with some arbitrary random number then call destroy_bitmap will do bad things. Snippet from destroy_bitmap:

void destroy_bitmap(BITMAP *bitmap)
{
   if (bitmap) {
      ...stuff
      free(bitmap);
   }
}

Birdeeoh

Yes - but there's a big difference between a NULL pointer -

BITMAP* bmp = 0;
destroy_bitmap( bmp );

and an already freed ptr -

BITMAP* bmp = load_bitmap( "somebitmap.bmp" );
destroy_bitmap( bmp );
destroy_bitmap( bmp );

Doing this will crash yuh.

Neil Walker

Yes, that's what I said. If you free a pointer, it doesn't automatically give itself a value of 0. If you code properly, as in ensuring your pointers are either valid or null:

BITMAP* bmp=NULL;
...
...
destroy_bitmap(bmp);
bmp=NULL;

Then all will be well.

Murat AYIK

Does "delete" have the same behaviour? I use it without any checks:o

Derezo

delete has the same behaviour. Always set them to NULL after you delete them, if you plan to use them again.

HoHo

If I remember correctly then NULL has been deprecated and regular 0 should be used instead. I don't remember if this is only in C++ or in C too though.

Indeterminatus
ISO/IEC 14882:1998, Section 18.1.4 said:

The macro NULL is an implementationdefined
C++ null pointer constant in this International Standard
(4.10). Possible definitions include 0 and 0L, but not (void*)0.

Not the newest source, I admit.

Derezo
Quote:

If I remember correctly then NULL has been deprecated

Then why did you use it to begin with anyway? ::)
See your first post :P

MSVC 8 complains about a lot of things being deprecated. itoa(), sprintf(), _snprintf(), and more. It does not complain about NULL. If it is deprecated, google doesn't favour the pages that explain it.

In C, 0 is not NULL. In C++, NULL is defined as 0. It just makes more sense to use NULL (I want a null pointer, not zero).

HoHo
Quote:

Then why did you use it to begin with anyway?

How to you spell "0"? I know it can be written as "zero" or "null", possibly something else too :)

Quote:

MSVC 8 complains about a lot of things being deprecated.

As I've heard it does. As it doesn't like standards a lot then I'm not suprised it doesn't do anything about the NULL macro. Though I'm not sure if any other compilers do.

Quote:

In C, 0 is not NULL.

But it has to be something that evaluates to 0. If it doesn't it might be a bit difficult to use in conditionals like if (blah) bleh();

Murat AYIK

I found this in MinGW/stddef.h:
#define NULL __null

I tried adding this to my prog:
#define __null 0

It doesn't complain but this is also weird. Then what is "__null"? (or what was:))

Derezo

I believe it is (void*)0 in C. Could be wrong.

Quote:

How to you spell "0"? I know it can be written as "zero" or "null", possibly something else too :)

It's a case sensitive argument? :P

Milan Mimica

Probably some kind of compiler extension.

Murat AYIK

Why can't I get this thing to crash?!

1#define msj allegro_message
2#include <allegro.h>
3 
4int main()
5{
6 allegro_init(); //set_gfx_mode(GFX_TEXT, 0,0,0,0);
7
8 int *ptr;
9
10 msj("newing");
11 ptr = new int;//[5];
12 msj("newed\n%d", ptr);
13
14 delete[] ptr; //delete ptr;
15 msj("deleted\n%d", ptr);
16 
17 delete[] ptr; //delete ptr;
18 msj("deleted again\n%d", ptr);
19 
20 ptr = NULL;
21 msj("ptr/NULL = %d", ptr);
22
23 ptr += 2;
24 msj("ptr_int +2 = %d", ptr);
25 
26 return 1;
27} END_OF_MAIN()

Evert

`Proper' programming practice (according to some) says that in C++, one should use 0 instead of NULL also for pointers (don't ask me why).
In C, a pointer that is NULL evaluates to the boolean value 0 and an integer of 0 assigned to a pointer will set the pointer to NULL. That said, wether or not NULL is actually 0, (void *)0 or something else entirely is platform dependent.

Bob
Quote:

Why can't I get this thing to crash?!

Because you're relying on undefined behavior. Undefined behavior may mean that your program will work as expected just as well as making your computer burst into flames. You don't know which (or if there is anything in between), and the results don't need to be consistent from run to run.

Birdeeoh

Murat AYIK:

As Bob already pointed out, "undefined behavior" is just that - undefined. Early when I said "IT IS FATAL" or something like that, my point was twofold. A - it doesn't cause memory leaks as originally claimed, but rather the error would be a fatal fault and B - say something is "FATAL" usually encourages people not to do it ;)

It PROBABLY won't help you get a crash, but also try

void* data = malloc( 1024 );
free( data );
free( data );

if you're trying to demonstrate this bad behavior. But it's also quite possible it won't bite you until you accidentally do it in a complex program :)

Murat AYIK

OK, I just wanted to see what would happen during the dying process:)

Also neither new nor the malloc example crashed in MinGW or Turbo C++ 3.0 . Damn compilers! They don't produce miserable executables when you need one:P

So using zero or a #define trick would be safe, right?

OICW

Destroying a previously freed bitmap will probably end in segmentation fault, definately under Win2k and XP. This should work:

DATAFILE *gfx;
BITMAP *bmp;

gfx = load_datafile("blah.dat");
bmp = (BITMAP *)gfx[OBJECT].dat;

unload_datafile(gfx);
destroy_bitmap(bmp);  // at this point it will die by horrible death

Thread #569034. Printed from Allegro.cc