intmagicValue=0;boolMagicValueHelper(inta){magicValue=a;returntrue;}intMagicValue(){if(MagicValueHelper){// notice how this is not a valid function call, as im missing the parameter}returnmagicValue;}
Multiple calls to MagicValue() from anywhere in a maps script will always return the same value.
Test ive conducted have lead me to believe that the value returned is some internal code pointer, probably where to jump to should the if statement evaluate to true.
This appears to reveal the stack space remaining for Galaxy's memory.
To that, I give you...
intlibStack_SpaceRemaining=0;boollibStack_Helper(inti){libStack_SpaceRemaining=i;returntrue;}// Returns in bytes the free stack space remaining.intlibStack_GetFreeStackSpace(){if(libStack_Helper){}returnlibStack_SpaceRemaining;}
Call "libStack_GetFreeStackSpace()" to find out how much space you have left in the stack, in bytes. :)
Could be useful to some of these very large projects that think they're converging on that script limit.
Doesn't reveal the heap space remaining, though.
Also looks like for every level you go deeper into the call stack, you lose 28 bytes of the stack, excluding any parameters.
How in the world did you figure that out so quickly? >_> My mind is looping infinitely just trying to understand how that "function" can take nothing without giving some sort of compiler error.
Great find. You gotta love Blizzard for these things :D They always unwillingly hide such little gimmicks for us.
Although I'm a little bit puzzled as to why libStack_SpaceRemaining becomes the address of the current stack instead of it's content.
Maybe they added this to act as a safe-guard against uninitialized variables, or they initialize the content of the entire stack with the address of the respective cell..
My friend tried this out on visual C. Apparently no compiler errors are generated either. It seems to just call the magic function and taking the return value immediately, ignoring the fact that an input is required. The return value is of course, 1 (true)
So yeah.. its not exclusively blizzard >_>
Edit: I'm not really following on this stack thing.. Do you guys mean that whenever that function is called, it will display a different value for the global variable that was used? The value of course being the address of the current stack.
A function without the following parenthesis is simply a function pointer to the memory address of the function. And there is actually no return value in this case:
voidmyFunc(){}voidmain(){if(myFunc){//Blah blah}}
That's perfectly valid. As you can see myFunc doesn't even need a return value.
With this set-up myFunc will not be called. Instead, the memory address of myFunc will be taken.
So if you put in the numbers it turns into something like:
if(0x123456){//<- the memory address.
//Blah
}
And since the memory address is always != 0 it's always true and the if-block will always be executed.
But in Galaxy it seems the function is executed even though it isn't explicitely called.
Maybe it's a remnant from the time Galaxy had pointers. I believe it also had function pointers.. and when they removed pointers they just changed it to executing the function instead of getting it's address.
What Motive means by going deeper into the stack is that every time you call a function inside a function the system needs to have some more memory to store all variables/parameters for this new function call. But the vars/params for the calling function must stay too, because they're still needed.
So the system allocates a bit of memory from the stack and deallocates it once the function finished. So obviously every function call inside a function call takes up some additional memory, because the other functions couldn't be deallocated yet.
Theoretically you could exceed your memory limit by just making a function call itself recoursively. But you'd probably hit the execution limit before that :3
My friend tried this out on visual C. Apparently no compiler errors are generated either. It seems to just call the magic function and taking the return value immediately, ignoring the fact that an input is required. The return value is of course, 1 (true)
So yeah.. its not exclusively blizzard >_>
Tried it out in C as well. It seems to return the address of the function there, but I do not know enough C to know for sure (now that I think of it, I may know a way). So I guess what s3rius said makes most sense, that it has to do with that they used to have pointers.
EDIT:
Ok, I have confirmed it with a little help from a friend :P. This is the C code, if anyone is interested.
Yup, in C/Cxx this mechanism would just be comparing the memory address of the function. What Galaxy is doing is completely unrelated and very different.
We want to know about the invisible int after the function pointer.
2097088 byte ??
I add a second variable don't know what it means
int[16]libStack_SpaceRemaining;boollibStack_Helper(inta,intb,intc,intd,inte,intf,intg,inth,inti,intj,intk,intl){libStack_SpaceRemaining[0]=a;libStack_SpaceRemaining[1]=b;libStack_SpaceRemaining[2]=c;libStack_SpaceRemaining[3]=d;libStack_SpaceRemaining[4]=e;libStack_SpaceRemaining[5]=f;libStack_SpaceRemaining[6]=g;libStack_SpaceRemaining[7]=h;libStack_SpaceRemaining[8]=i;libStack_SpaceRemaining[9]=j;libStack_SpaceRemaining[10]=k;libStack_SpaceRemaining[11]=l;returntrue;}// Returns in bytes the free stack space remaining.intlibStack_GetFreeStackSpace(inta){if(a==0){if(libStack_Helper){}}returnlibStack_SpaceRemaining[a];}
Galaxy is not C/Cpp.
I fail to see a reason for the "invisible i" that is taken from the TOS AS A VALUE to be evaluated to the current TOS position. Did any of you actually verify this by trying to fill up the file with crap till it exploded and checking that return value every time?
Recursion: I REALLY hope they implemented tail-call optimizations...
Your text is green because the + + in C + + is interpreted as a text format command in WikiCreole. Just put a space inbetween it :)
To the issue at hands:
Unfortunately it seems the returned number is ONLY for the call stack.
You can stuff as much variables and whatnot into the map and it'll still show 2 MB free space.
The number only decreases once you go deeper down the call stack.
Function with 1 recursion: 2097096
Function with 10 recursions: 2096764
For each recursion there'll be 28 byte deducted (function pointer and return value probably) and another 4 byte for every integer that you pass as parameter.
Guess we put on the party hats too early.
That value is near to useless.
That also suggests that no tail-call optimization is going on.
Maybe this can be used to see how much of the local stack has been allocated. IIRC, the maximum was 32KByte. This would also explain why its allocated from 2^21 downwards.
Also, its nice to see this make the front page, but that might have been an overreaction. Its an interesting bug, but, as it turns out, almost completely useless.
Next time, lets just do the testing before putting it up on the front page.
Multiple calls to MagicValue() from anywhere in a maps script will always return the same value.
Test ive conducted have lead me to believe that the value returned is some internal code pointer, probably where to jump to should the if statement evaluate to true.
Credits to JademusSreg who stumbled across this.
This appears to reveal the stack space remaining for Galaxy's memory.
To that, I give you...
Call "libStack_GetFreeStackSpace()" to find out how much space you have left in the stack, in bytes. :)
Could be useful to some of these very large projects that think they're converging on that script limit.
Doesn't reveal the heap space remaining, though.
Also looks like for every level you go deeper into the call stack, you lose 28 bytes of the stack, excluding any parameters.
@MotiveMe: Go
How in the world did you figure that out so quickly? >_> My mind is looping infinitely just trying to understand how that "function" can take nothing without giving some sort of compiler error.
I don't know, but it was a bug that stumped me for half a day precisely because it doesn't raise a compile error. =\
Great find. You gotta love Blizzard for these things :D They always unwillingly hide such little gimmicks for us.
Although I'm a little bit puzzled as to why libStack_SpaceRemaining becomes the address of the current stack instead of it's content.
Maybe they added this to act as a safe-guard against uninitialized variables, or they initialize the content of the entire stack with the address of the respective cell..
@s3rius: Go
My friend tried this out on visual C. Apparently no compiler errors are generated either. It seems to just call the magic function and taking the return value immediately, ignoring the fact that an input is required. The return value is of course, 1 (true)
So yeah.. its not exclusively blizzard >_>
Edit: I'm not really following on this stack thing.. Do you guys mean that whenever that function is called, it will display a different value for the global variable that was used? The value of course being the address of the current stack.
@FuzzYD: Go
But that's because of a different reason.
A function without the following parenthesis is simply a function pointer to the memory address of the function. And there is actually no return value in this case:
That's perfectly valid. As you can see myFunc doesn't even need a return value.
With this set-up myFunc will not be called. Instead, the memory address of myFunc will be taken.
So if you put in the numbers it turns into something like:
And since the memory address is always != 0 it's always true and the if-block will always be executed.
But in Galaxy it seems the function is executed even though it isn't explicitely called.
Maybe it's a remnant from the time Galaxy had pointers. I believe it also had function pointers.. and when they removed pointers they just changed it to executing the function instead of getting it's address.
What Motive means by going deeper into the stack is that every time you call a function inside a function the system needs to have some more memory to store all variables/parameters for this new function call. But the vars/params for the calling function must stay too, because they're still needed.
So the system allocates a bit of memory from the stack and deallocates it once the function finished. So obviously every function call inside a function call takes up some additional memory, because the other functions couldn't be deallocated yet.
Theoretically you could exceed your memory limit by just making a function call itself recoursively. But you'd probably hit the execution limit before that :3
Tried it out in C as well. It seems to return the address of the function there, but I do not know enough C to know for sure (now that I think of it, I may know a way). So I guess what s3rius said makes most sense, that it has to do with that they used to have pointers.
EDIT:
Ok, I have confirmed it with a little help from a friend :P. This is the C code, if anyone is interested.
Yup, in C/Cxx this mechanism would just be comparing the memory address of the function. What Galaxy is doing is completely unrelated and very different.
@MotiveMe: Go
So are there any benefits to this 'bug'?
I think it smells as some pointer remnant, too.
Still, could be nice to use. No idea for what, but who knows.
Whatever: damn Blizz, include pointers! ¬¬
We want to know about the invisible int after the function pointer. 2097088 byte ??
I add a second variable don't know what it means
Galaxy is not C/Cpp. I fail to see a reason for the "invisible i" that is taken from the TOS AS A VALUE to be evaluated to the current TOS position. Did any of you actually verify this by trying to fill up the file with crap till it exploded and checking that return value every time?
Recursion: I REALLY hope they implemented tail-call optimizations...
@moshewe: Go
Your text is green because the + + in C + + is interpreted as a text format command in WikiCreole. Just put a space inbetween it :)
To the issue at hands:
Unfortunately it seems the returned number is ONLY for the call stack.
You can stuff as much variables and whatnot into the map and it'll still show 2 MB free space.
The number only decreases once you go deeper down the call stack.
Function with 1 recursion: 2097096
Function with 10 recursions: 2096764
For each recursion there'll be 28 byte deducted (function pointer and return value probably) and another 4 byte for every integer that you pass as parameter.
Guess we put on the party hats too early.
That value is near to useless.
That also suggests that no tail-call optimization is going on.
@s3rius: Go
Sad indeed. It's something I expect first-year undergrads to be capable of. Truly, blizz, you disappoint me.
Maybe this can be used to see how much of the local stack has been allocated. IIRC, the maximum was 32KByte. This would also explain why its allocated from 2^21 downwards.
Also, its nice to see this make the front page, but that might have been an overreaction. Its an interesting bug, but, as it turns out, almost completely useless. Next time, lets just do the testing before putting it up on the front page.
@Deaod: Go
Yes lol, slightly overreacting :p