Why does this work?

BlitzMax Forums/BlitzMax Programming/Why does this work?

Leiden(Posted 2006) [#1]
Local i:Float[]
Test(i)
Print i[9999]

Function Test(t:Float Ptr)
	t[9999] = t[9999] + 100
End Function


Shouldnt that give a Unhandled Memory Exception? That array (i) should be empty.


Who was John Galt?(Posted 2006) [#2]
Are you running in debug mode?


Leiden(Posted 2006) [#3]
I know that it gives an error in debug, but its printing the correct value and running fine in release. It doesnt make sense?


ImaginaryHuman(Posted 2006) [#4]
You haven't told Blitz how big the array should be, all you have is an empty `float array pointer` with no data space defined. It's an empty array with no space to store anything, as if i:Float[0] or i=Null

Local i:Float[10000]

for example should remove the error

Or add a line:

i=i[..10000]

which creates a new i array and then the old i float ptr becomes garbage


Leiden(Posted 2006) [#5]
I know that its an empty array, I'm just wondering why I'm able to index outside of its bounds in release mode. If its a null array and I'm setting t[9999] (non-existant reference) to 100 and its then returning 100 from the non-existant index, well... that doesn't make sense :/

t[9999] presumably has no memory allocated, so how is 100 getting stored? Why is 100 being printed? Shouldnt it crash?


SculptureOfSoul(Posted 2006) [#6]
I noticed a problem similar..well, related perhaps... to this a while back when I was whipping up a tile engine. In debug mode the game would crash when walking off the edge of the map, and in release it was wrapping around to the other side of the array (only when exiting the map vertically though, strangely enough)

Of course, that was an older version of Blitzmax.


Brendane(Posted 2006) [#7]
The debug version has bounds checking built in. The release version does not.

The code Local i:Float[]
creates an array object and assigns it with the 'empty array' (an internal global empty array object - this exists as a static object in memory).

Now, if you read values from this array they are indexed from this empty array's address... anything which follows it in memory may or may not be a valid address for the process. If it is, you get the value at the address - if not you will get an access violation exception.


Leiden(Posted 2006) [#8]
Ah ok, so Max has a built in empty array that it just assigns the i:float[] to point to until it is constructed?

I tried the same thing in C++ and it gave me "i : unknown size". Thats in release. I would prefer it if Max did check bounds in release -- but there must be a good reason it doesnt.


ImaginaryHuman(Posted 2006) [#9]
In release you are taking away the checking by not doing debug mode. Thats the whole point, you should use debug to check for bugs like this and then release mode when you're sure YOUR code is safe.

In the past writing to an undefined offset in an empty array would've written somewhere in memory and caused a crash.


Leiden(Posted 2006) [#10]


So to acurately describe what is happening above, say, Orange is my actual array and size, lets say one byte. Green is free memory that currently isnt being allocated anywhere. Red is memory that has been allocated by some other program, or some other variable in the program.

So is it correct to say, if I write outside of the arrays index, to a green area of memory, it would still function as if the array was large enough to have that variable in index, provided the program doesnt assign some data to that area as it doesnt know its being referenced. But if I went and tried to write data to the array that happened to be in the red area, that would give me an Unhandled Memory Exception right?


Brendane(Posted 2006) [#11]
In Windows at least, every process has it's own address space. This is accomplished by virtual memory, every process can (theoretically) use all 4gb of addressable memory (in a 32bit system). The windows memory manager handles the mapping of the virtual addresses to physical addresses as and when those memory addresses are required to be accessed. (using the swap file)

That said, in your diagram the red blocks wouldn't exist (because every process has no knowledge of the virtual addresses allocated by another process, nor does it care).

It is correct to say that some memory is allocated to your process (the exe itself and all it's data areas are mapped in), the process itself has thread storage areas, it's own process heap, and dynamically allocated memory etc etc.

To answer your question, any memory *allocated* to your application can be accessed (in your case, the exe contains a data section containing the emptyarray which is simply mapped into virtual memory - ie allocated to your process).

If you read/write to any unallocated area, or write to an allocated but readonly area you will get an access violation.


Leiden(Posted 2006) [#12]
So I can write in memory allocated to my program? That said, Say the diagram is the total memory allocated to my program, green blocks are free memory space, orange is occupied with my array, and red is allocated to some other variables. Now, in my program, can I write outside of my arrays bounds (a single block in this case) and into the green blocks, not legally, but is this the case of whats happening when I am able to read/write to 't[9999]'. That said, I can continue to write to my array until I reach a allocated block (red) then it will MAV?


Dreamora(Posted 2006) [#13]
Perhaps it MAVs, perhaps not. But your data will for nearly sure be bogus, because you have to know why you do such trash in your code, not Windows.
Which means: don't write on references you haven't initialized or be aware that you are doing something highly critical (and stupid)

Windows will throw a MAV if you try to access / modify data that does not exist (after file load) or which you aren't allowed to access (kernel memory and protected memory, as well as trying to access your apps code in memory which is forbidden as well)

As mentioned above: Use debug mode, this will show you all errors.
And step back from using Ptr within BM. They exist, but they are not the prefFered nor the stable way of using BM. References are similar to pointers, but they are type safe and managed and thus will never lead to problems like the one were are actually talking about here.
Thats something thats more or less a C++ hacker problem (hacker because one thats programs this way in C++ can't be seen as a programmer even on noobish level)


FlameDuck(Posted 2006) [#14]
I would prefer it if Max did check bounds in release -- but there must be a good reason it doesnt.
Speed.


Dreamora(Posted 2006) [#15]
If you want debug checks, do all your calls in Try - Catch blocks ... that way at least some errors will throw something catchable ... but you will lose quite some speed.

And no, Array and Loops won't fire errors there, as their debug modules are not compiled into the release version (which means, theoretically you could check if you can add it through manual import)