gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > sprintf bug in DKP

#129796 - Noda - Sun May 27, 2007 12:57 pm

Hi,

for the second time, I experienced problems with the sprintf command:

- the first time was in my game, Warcraft Tower Defense, using in some part of the game just caused the game freeze at launch (and yes before the function is used!). Just solved this by included my own sprintf code and not using the DKP one, as I first thought of an incompatibility with PALib.

- this time, on a libnds only project, using it at some time on the arm7 makes the binary crash on both no$gba and dslite (though only no$ report the crash ;)), and again the crash occurs at started before the function is actually called!
And strangely, it only occurs when I the string to print exceed a certain lenght: sprintf(text, "ok!"); works (no crash) when if I put sprintf(text, "blablablablabla"); it crashed :/
Again, I just added my own sprintf code and everything worked fine...


Maybe I'm not the only having issues with that?

#129797 - kusma - Sun May 27, 2007 1:19 pm

How much memory have you allocated for text?
...And how do you know that the crash occurs before the function is called?

#129799 - Noda - Sun May 27, 2007 2:16 pm

text = (char*) malloc(256);

and all my string are under 256 in size, the problem is not here as it works when I use my own sprintf function (code from a linux distrib).

And obviously I know that it crash before executing the sprintf because it crashes at start (nothing is displayed), way before going into the game...

and it crashes even with something like that:

(init code)
...
while(1); // infinite loop to prevent sprintf execution...
...
sprintf(...);

#129800 - kusma - Sun May 27, 2007 2:21 pm

My best guess would be that you're running out of stack-space. I'm pretty confident that the sprintf in newlib isn't broken like that.

#129802 - Noda - Sun May 27, 2007 2:30 pm

..And again, I'm pretty confident that it's not the case, I have a LOT of free heap space... then why a simple sprintf code copied from a linux dist would work in that case?

And why would it crash at start, prior to the execution of anything???

#129804 - kusma - Sun May 27, 2007 2:39 pm

Noda wrote:
..And again, I'm pretty confident that it's not the case, I have a LOT of free heap space...

Free heap does not mean you have plenty of stack on embedded systems. However, it might be something else, but this smells like stack under-run or corruption to me. Blaming the compiler and/or the standard-library for bugs is in most cases a big mistake.
Noda wrote:
then why a simple sprintf code copied from a linux dist would work in that case?

No symptoms of bugs does not mean there are none. Vararg-functions have an unfortunate habit of hiding stack-related bugs. Another thing that can vary between implementations of the same function can be memory-footprint.
Noda wrote:
And why would it crash at start, prior to the execution of anything???

Definitely not due to a bug in sprintf(), that's for sure. If it's a bug in the code, how can it crash before it reaches it?

#129805 - Noda - Sun May 27, 2007 2:44 pm

kusma wrote:
Noda wrote:
..And again, I'm pretty confident that it's not the case, I have a LOT of free heap space... then why a simple sprintf code copied from a linux dist would work in that case?

Free heap does not mean you have plenty of stack on embedded systems. However, it might be something else, but this smells like stack under-run or corruption to me. Blaming the compiler and/or the standard-library for bugs is in most cases a big mistake.

But in that case, it's an amateur devchain, not a professional one... and bugs of this kind exists yes, even sometimes in well-known compiler distribs...

kusma wrote:

Noda wrote:
And why would it crash at start, prior to the execution of anything???

Definitely not due to a bug in sprintf(), that's for sure. If it's a bug in the code, how can it crash before it reaches it?


Then how do you explain that:
[code, no sprintf here]
while(1);
sprintf(...);
--> crash

and

[code, no sprintf here]
while(1);
//sprintf(...);
--> works, the code above runs fine...

#129806 - kusma - Sun May 27, 2007 2:53 pm

Noda wrote:

But in that case, it's an amateur devchain, not a professional one... and bugs of this kind exists yes, even sometimes in well-known compiler distribs...

Both gcc and newlib has massive market adoption in the embedded space. Believe me, this code has been tested well. While it might be true that devkitPro is an amateur-build of gcc and newlib (I don't know what Dave's work situation is), I don't see how that should matter.

Noda wrote:

Then how do you explain that:
[code, no sprintf here]
while(1);
sprintf(...);
--> crash

and

[code, no sprintf here]
while(1);
//sprintf(...);
--> works, the code above runs fine...

There's many different things that happen there. For instance, the compiler might push the parameters for sprintf on the stack before entering the while-loop. Another thing that happens, is that if this is the only function using sprintf() in your program, sprintf() must be included into the binary. This change the memory-layout for the program. You might have some other bug that triggers due to this memory-layout change. There's about a million other explanations, none of them will blame the code in the function that has not yet been reached.

#129809 - Noda - Sun May 27, 2007 3:57 pm

kusma wrote:
Noda wrote:

But in that case, it's an amateur devchain, not a professional one... and bugs of this kind exists yes, even sometimes in well-known compiler distribs...

Both gcc and newlib has massive market adoption in the embedded space. Believe me, this code has been tested well. While it might be true that devkitPro is an amateur-build of gcc and newlib (I don't know what Dave's work situation is), I don't see how that should matter.


That doesn't means that bugs are not possible... for example, some bugs are well-know in the optimizer part of GCC, some programs don't work with -O3 ennabled wheras they works with -O2...

Noda wrote:

Then how do you explain that:
[code, no sprintf here]
while(1);
sprintf(...);
--> crash

and

[code, no sprintf here]
while(1);
//sprintf(...);
--> works, the code above runs fine...

There's many different things that happen there. For instance, the compiler might push the parameters for sprintf on the stack before entering the while-loop. Another thing that happens, is that if this is the only function using sprintf() in your program, sprintf() must be included into the binary. This change the memory-layout for the program. You might have some other bug that triggers due to this memory-layout change. There's about a million other explanations, none of them will blame the code in the function that has not yet been reached.[/quote]

so something better for:

[code]
sprintf(text, "something");
while(1);
sprintf(text, "someting else);
-> crash
-----------------------
[code]
sprintf(text, "something");
while(1);
//sprintf(text, "someting else);
-> works
-----------------------
[code]
sprintf(text, "something");
while(1);
mysprintf(text, "someting else);
-> works

In all cases, parameters may be pushed on the stack the same way and sprintf is included...

Just to remind that's the second time I have this bug, in totally different projects... I'll try to make a simple "crash example" so you will be happy to admit it can only be something wrong with this function...

#129813 - Lazy1 - Sun May 27, 2007 4:10 pm

I also the same sprintf problem on the arm7 but gave up after a while, hope you get it working.

#129814 - kusma - Sun May 27, 2007 4:15 pm

Noda wrote:
That doesn't means that bugs are not possible... for example, some bugs are well-know in the optimizer part of GCC, some programs don't work with -O3 ennabled wheras they works with -O2...

Are you sure you're not thinking of the fact that -O3 turns on some options that breaks some kinds of code. One typical example of this is the strict aliasing rule. With -O3 turned on, the code needs to conform to the strict aliasing requirements of C++. This is not a bug, this is expected and defined operation.
Noda wrote:

[lots of irrelevant code stripped away]
In all cases, parameters may be pushed on the stack the same way and sprintf is included...

I didn't say it was the only possible source of the bug, now did I? I just argued that bugs in sprintf couldn't be blamed for a crash when it hadn't even been run yet. And besides, things does change there also. Case 2 has a different stack-layout than case 1 and 3, and Case 3 has a function more than Case 1 and 2.
Noda wrote:

Just to remind that's the second time I have this bug, in totally different projects... I'll try to make a simple "crash example" so you will be happy to admit it can only be something wrong with this function...

Please do.

#130003 - wintermute - Wed May 30, 2007 1:09 am

Noda wrote:
..And again, I'm pretty confident that it's not the case, I have a LOT of free heap space... then why a simple sprintf code copied from a linux dist would work in that case?

And why would it crash at start, prior to the execution of anything???


Because you're using newlib sprintf on the ARM7 where you have a total of 96K of available RAM. To my mind, 96K hardly qualifies as a LOT especially considering everything must fit in there.

Back it the dim dark days when I learned to program 96K may have been an incredible amount of memory but C was just about unheard of for games dev then.

I'm not entirely convinced that using standard library functions on the arm7 is a good idea at all. Offhand I can't think of one single good reason why you would want to use sprintf on the arm7 - certainly not in release code.

Newlib is incredibly convenient most of the time but, despite having been developed for embedded systems, stdio functions are a lot heavier than you'd expect.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#130030 - Noda - Wed May 30, 2007 9:59 am

Then it might be the cause for the arm7 use case (even I doubt as I use very little ram here and my binary is only 50k), but the first time I experienced crashes (of exactly the same kind, at start) was using it on my Warcraft game on the arm9, so no memory problem here (more than 1Mb of ram was free) :/

But I definitely agree that newlib stdio functions are quite heavy, and I wonder why as for example the sprintf function I've picked from a linux distrib doesn't cause any problems and its compiled size is quite smaller than stdio one :/

#130036 - wintermute - Wed May 30, 2007 11:30 am

You do realise that 50k is a shade over 52% of the available RAM and that the size of the binary is only part of the memory used before your app starts allocating RAM?

Noda wrote:

Just to remind that's the second time I have this bug, in totally different projects... I'll try to make a simple "crash example" so you will be happy to admit it can only be something wrong with this function...


That would be the best approach. I need a testcase to prove or disprove a devkitARM bug.

kusma wrote:

While it might be true that devkitPro is an amateur-build of gcc and newlib


I prefer to think of devkitPro as professional toolchains at amateur prices :P
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#130041 - kusma - Wed May 30, 2007 1:41 pm

wintermute wrote:

kusma wrote:

While it might be true that devkitPro is an amateur-build of gcc and newlib


I prefer to think of devkitPro as professional toolchains at amateur prices :P

It must be! It has "Pro" in it's name!