View Full Version : [SOLVED] GCC (g++) Memory allocation issues
NovaCoder
23 July 2010, 03:38
Ok this is really starting to annoy me now :(
I'm trying to port this project to 68k (020) using gcc V2.9.5.3 (CubicIDE) and I'm having memory issues. The code is a large C++ project with a mixture of new(), malloc() and calloc().
There seems to be some kind of arbitrary limit of memory that causes the program to crash. The only way I've managed to get it run is to convert all of the calls from malloc()/calloc() to the AllocMem() which I obviously shouldn't have to do.
Currently I've got the compiler setup to store the data as 'FAR', does it need to be set to 'EXTRA FAR' or something silly like that?
I can't be the only one to ever come across this issue :shocked
Help!
Leffmann
23 July 2010, 05:20
The far qualifier is a remnant from the early x86 architectures which used a segmented memory model. The M68K architecture has always used a flat memory model, and the far qualifier is useless here and has no effect on your pointers.
Does the code crash inside the malloc/calloc calls or because you don't check their return values? Or do you mean that you simply run out of memory when you use malloc/calloc instead of AllocMem? If AllocMem works, then why not just use that?
It's possible that GCC's standard library arbitrates calls to malloc/calloc to handle tiny allocations more efficiently, but I think an error of this kind wouldn't have slipped through.
NovaCoder
23 July 2010, 06:58
It's driving me crazy (ok I was already a little crazy before I started Amiga coding but there you go).
My other problem is that I can't really debug it (or at least step-through the code).
The only thing I know so far for sure is:
1) Replacing all the calls from calloc to AllocMem(FAST_MEM) gets it working.
2) The code seems to be run though a number of calloc statements before it blows up (reboots the computer!).
Other people must have had this issue.....I can't be that unlucky ;)
The code doesn't check the return values from the calls to calloc/malloc.
My other problem is that I can't really debug it (or at least step-through the code).
When you get a reproduceable crash you should be able to find the crash location, even without a debugger.
What kind of Guru is it? Illegal instruction (80000003) or memory corrupted (81000005), etc?
Also use Enforcer and MungWall or similar tools to provoke memory failures early, and replace AllocMem/calloc by an own function which checks the return value.
1) Replacing all the calls from calloc to AllocMem(FAST_MEM) gets it working.
Without MEMF_CLEAR? That's strange. Rememer that calloc() will return zeroed memory!
2) The code seems to be run though a number of calloc statements before it blows up (reboots the computer!).
Oh. So there is no Guru? I guess your program is writing to unallocated memory, or exceeds the limits of the allocated memory chunks.
As stated above, use Enforcer/MungWall. And try to allocate twice the memory requested and see if it changes anything. I guess it's just luck when AllocMem doesn't crash, because the memory is allocated in a different order.
NovaCoder
23 July 2010, 12:28
I've noticed in WINUAE it writes 'BI_TARGETTED' to the command window...not sure if that helps.
I was setting MEMF_CLEAR when I called AllocMem(FAST_MEM) eg (AllocMem(FAST_MEM|MEMF_CLEAR)
Do you think that could have made a difference?
It is possible that your app is broken (using free twice on a zone or something like that) and there's different behaviour between AmigaOS calls and gcc calls.
Have you used memminister to ensure that all memory is freed on exit? Maybe some free() fails in the way and corrupts the memlist.
I've worked a lot with gcc (on Linux/Windows). When you're lucky, it crashes in the free() call. When you're not lucky it crashes in the next malloc()!!
NovaCoder
26 July 2010, 01:00
Ok I think I've found the problem at last.
In parts of the code it calls calloc() but passes in zero for the number variable (the first parameter). In other implementations this would just result in no memory being allocated and calloc() would simply return NULL but in gcc 68k it blows up!
Oh well, glad I've finally figured this one out after all this time.
matthey
26 July 2010, 05:15
The Amiga built in memory allocation functions are more friendly. They handle 0 bytes just fine. It wouldn't be that difficult to switch to them. exec/AllocVec() is especially easy to use. It tracks the size of the allocation making it easier to use than exec/AllocMem().
It's probably more polite to allocate without the MEMF_FAST flag to allow for users with no fast ram and that run out of fast mem. Just set MEMF_CLEAR if you want the memory cleared or MEMF_ANY (0L) if you don't need it cleared.
reminds me of that bernd has built a workaround for something like this into his ixemul.lib. mem allocations of 0 seem to be quite a frequent bug in nix progs.
Toni Wilen
27 July 2010, 12:02
malloc and friends are allowed to return either NULL or some "dummy" pointer that free() accepts when allocation size = zero. (afaik zero size was originally undefined)
I've noticed in WINUAE it writes 'BI_TARGETTED' to the command window...not sure if that helps.
This only means program did something seriously bad and JIT got confused. (JIT and debugging is not very good combination)
tygre
06 January 2012, 22:08
Hi there!
In my never-ending ;) quest to recompile THTTPd v2.21b with PHP v4.2.3, I succeeded in compiling the beast but I got from times to times this error from IXEmul (v63.1): a dialog box opens stating "realloc: start of block corrupt" with only one button "Abort". When I click "Abort", I got the requester from the OS stating that the "memory header not located"...
Could anyone guide me in understanding and fixing this problem. (I compile PHP and THTTPd without any optimisations.)
Thanks in advance!
Tygre
tygre
07 January 2012, 01:35
Here are some more details and a code snippet illustrating my problem:
#include <stdio.h>
int main()
{
printf("Hello World!\n");
void* ptr = malloc(1000);
// realloc(ptr, 10000);
free(ptr);
printf("Goodbye.\n");
return(0);
}
With IXEmul v63.1 and v48.0, the code above works as expected with the commented line. If the line is uncommented, the IXEmul library reports this error "realloc: start of block corrupt". I simply compile this code using:
m68k-amigaos-gcc alloc.c -o alloc
Is this a known problem? Did anyone encounter it before?
I guess I will have to "rewrite" realloc in PHP using malloc and memcpy...
Please, let me know what you think! :help
Tygre
Leffmann
07 January 2012, 03:54
Never seen that before, but one cause could be that you may be freeing the wrong memory; realloc() returns a new pointer which you must always accept, because there's no guarantee that the new block will start at the same address.
(also, if you want to be really compliant then you should include stdlib.h since that's where the memory allocation functions are declared)
tygre
07 January 2012, 14:47
Thank for your answer Leffmann... I did some more tests and my real problem is that realloc does not always cause this problem... it can work fine for several runs and then, all the sudden, boom :( So it is hard to track what is happening...
Could it be a wrong combination of GCC and IXEmul?
My GCC says:
Reading specs from /usr/local/amiga/lib/gcc/m68k-amigaos/3.4.0/specs
Configured with: ../gcc-3.4.0/configure --prefix=/usr/local/amiga --target=m68k-amigaos --enable-languages=c,c++,objc --enable-haifa --enable-sjlj-exceptions --disable-shared --disable-libstdcxx-pch
Thread model: single
gcc version 3.4.0
(I found it Zerohero's web site (http://www.zerohero.se/cross/os3.html).)
:help
PS. I found a thread (http://eab.abime.net/showthread.php?t=53987&highlight=ixemul) about a (maybe) similar problem... unfortunately, it states that IXEmul should work find with allocating a size of zero...
Toni Wilen
07 January 2012, 14:59
Your problem (as was already said) is wrong usage of realloc(). It may return original address or it may return new address. Depends on available memory, memory fragmentation and so on..
Also note that realloc() can fail.
tygre
07 January 2012, 15:24
Thanks Toni but my real problem is that the crash occurs "randomly"...
I am trying to port THTTPd, which works fine on Unix and which has already been ported by LouiSe (but I must "re-port" it because of changes that I will make to it) so what could be the cause of the crashes?
Is Unix more lenient than AmigaOS? If so, how come would LouiSe's port work fine? Sorry for such general questions but I could use any hints right now... :banghead
PS. And again thank to you and Leffmann for pointing out my mistakes in my code snippet :) that should be:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello World!\n");
void* ptr = malloc(0);
ptr = (void *) realloc(ptr, 100);
free(ptr);
printf("Goodbye.\n");
return(0);
}
tygre
07 January 2012, 15:26
Sorry for kind of duplicating this thread... I started dumbly a thread about what I realise is a similar problem (http://eab.abime.net/showthread.php?p=794783)...
prowler
07 January 2012, 15:41
Sorry for kind of duplicating this thread... I started dumbly a thread about what I realise is a similar problem (http://eab.abime.net/showthread.php?p=794783)...
Threads merged. :)
tygre
07 January 2012, 15:53
Thanks! You are too fast :)
Toni Wilen
07 January 2012, 17:53
Tried Mungwall or Enforcer to debug memory related errors?
tygre
07 January 2012, 20:03
Yes, I am running THTTPd with Enforcer in WinUAE. My problem is really that the crash happens kind of randomly, at least to my uneducated eyes ;)
I will try on my Classic Amiga, there, THTTPd seems to crash "faster" and more regularly...
Edit: Actually, I was mistaken (no surprise here! ;)): in WinUAE too does Enforcer report violations: when running Enforcer FILE=CON: and then thttpd, I get thousands of violations (?), such as:
LONG-WRITE to 00000100 data=00000000 PC: 1025F11E
USP: ...
Data: ...
Stck: ...
Stck: ...
Name: "Background CLI" CLI: "thttpd"
(Copied by hand from the CON:.)
Does this output mean that THTTPd is really busting the memory?
I am going to run SegTracker and save Enforcer's output to a file if one of you wouldn't mind looking at it :)
tygre
07 January 2012, 20:56
Here are parts of Enforcer's output: the first hundred "violations" are like that one:
BYTE-READ from 0E5C10BF PC: 102773DC
USP: 10BF26CA SR: 0000 SW: 0521 (U0)(-)(-) TCB: 10789918
Data: 00000000 0000000A 00000000 10BF7B70 00000012 0402C541 00000007 0E5C10BF
Addr: 0E5C10BF 00000026 10A97CF0 10BF28CC 10E67700 10BF2882 10279DE0 --------
Stck: 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC 10BF28C2 10BF288A
Stck: 10279DE0 0007102B FC8C10A9 7CE910BF 28C210BF 288A0000 00000000 00000000
----> 102773DC - "LIBS:locale.library" Hunk 0000 Offset 00001AF4
Name: "Background CLI" CLI: "thttpd"
and then, the next one (only one) is like:
LONG-READ from 5B03971A PC: 10A9A68A
USP: 10BF295A SR: 0010 SW: 0501 (U0)(-)(-) TCB: 10789918
Data: 5B039722 5B0396E8 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B0396E8 0015BDA4 000001D4 10BF398A 10E67700 10BF297E 10000830 --------
Stck: 10CED688 00000138 000009C0 10CED67C 10CED67C 10BF2992 10AC7C4A 10B6DDB0
Stck: 00000002 10BF29A2 10A9AAC4 5B0396E8 10BF8AF0 10BF8B70 00000001 10A99840
----> 10A9A68A - "thttpd" Hunk 0000 Offset 000212AA
Name: "Background CLI" CLI: "thttpd" Hunk 0000 Offset 000212AA
and then, the next dozen or so are like:
BYTE-WRITE to 5B039724 data=00 PC: 1037C0BE
USP: 10BF28E6 SR: 0004 SW: 0421 (U0)(-)(-) TCB: 10789918
Data: 00000000 00000010 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B039725 5B039724 000001D4 10BF398A 10E67700 10BF28F6 10000830 --------
Stck: 10AC78D0 5B039724 00000000 00000010 10BF290A 10AC7A1C 5B039722 5B039722
Stck: 54412546 10BF2992 10A996BE 0015BDA4 000001D4 4F460000 00E60000 015D0000
----> 1037C0BE - "LIBS:ixemul.library" Hunk 0000 Offset 0001892E
Name: "Background CLI" CLI: "thttpd"
finally, the last ones before the Guru are:
BYTE-WRITE to 5B039796 data=00 PC: 10A99870
USP: 10BF297E SR: 0000 SW: 0421 (U0)(-)(-) TCB: 10789918
Data: 0000003F 00000000 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B039796 5B0397B8 000001D4 10BF398A 10E67700 10BF298E 10000830 --------
Stck: 000001D4 10A9840E 10BF5B03 97962B00 10BF3906 10B2CFB2 0000003F 10BF2A96
Stck: 10BF2AB6 00000000 00000000 10B6DDB0 10BF7B70 00000000 00000000 00000000
----> 10A99870 - "thttpd" Hunk 0000 Offset 00020490
Name: "Background CLI" CLI: "thttpd" Hunk 0000 Offset 00020490
LONG-WRITE to 5B039798 data=00000000 PC: 10A99880
USP: 10BF297E SR: 0004 SW: 0401 (U0)(-)(-) TCB: 10789918
Data: 10BF2A96 5B039796 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B039798 10BF2A96 000001D4 10BF398A 10E67700 10BF298E 10000830 --------
Stck: 000001D4 10A9840E 10BF5B03 97962B00 10BF3906 10B2CFB2 0000003F 10BF2A96
Stck: 10BF2AB6 00000000 00000000 10B6DDB0 10BF7B70 00000000 00000000 00000000
----> 10A99880 - "thttpd" Hunk 0000 Offset 000204A0
Name: "Background CLI" CLI: "thttpd" Hunk 0000 Offset 000204A0
LONG-WRITE to 5B03979C data=00000000 PC: 10A99886
USP: 10BF297E SR: 0004 SW: 0401 (U0)(-)(-) TCB: 10789918
Data: 10BF2A96 5B039796 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B03979C 10BF2A9A 000001D4 10BF398A 10E67700 10BF298E 10000830 --------
Stck: 000001D4 10A9840E 10BF5B03 97962B00 10BF3906 10B2CFB2 0000003F 10BF2A96
Stck: 10BF2AB6 00000000 00000000 10B6DDB0 10BF7B70 00000000 00000000 00000000
----> 10A99886 - "thttpd" Hunk 0000 Offset 000204A6
Name: "Background CLI" CLI: "thttpd" Hunk 0000 Offset 000204A6
LONG-WRITE to 5B0397A0 data=00000000 PC: 10A9988C
USP: 10BF297E SR: 0004 SW: 0401 (U0)(-)(-) TCB: 10789918
Data: 10BF2A96 5B039796 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B0397A0 10BF2A9E 000001D4 10BF398A 10E67700 10BF298E 10000830 --------
Stck: 000001D4 10A9840E 10BF5B03 97962B00 10BF3906 10B2CFB2 0000003F 10BF2A96
Stck: 10BF2AB6 00000000 00000000 10B6DDB0 10BF7B70 00000000 00000000 00000000
----> 10A9988C - "thttpd" Hunk 0000 Offset 000204AC
Name: "Background CLI" CLI: "thttpd" Hunk 0000 Offset 000204AC
LONG-WRITE to 5B0397A4 data=00000000 PC: 10A99892
USP: 10BF297E SR: 0004 SW: 0401 (U0)(-)(-) TCB: 10789918
Data: 10BF2A96 5B039796 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B0397A4 10BF2AA2 000001D4 10BF398A 10E67700 10BF298E 10000830 --------
Stck: 000001D4 10A9840E 10BF5B03 97962B00 10BF3906 10B2CFB2 0000003F 10BF2A96
Stck: 10BF2AB6 00000000 00000000 10B6DDB0 10BF7B70 00000000 00000000 00000000
----> 10A99892 - "thttpd" Hunk 0000 Offset 000204B2
Name: "Background CLI" CLI: "thttpd" Hunk 0000 Offset 000204B2
LONG-WRITE to 5B0397A8 data=00000000 PC: 10A998A2
USP: 10BF297E SR: 0000 SW: 0401 (U0)(-)(-) TCB: 10789918
Data: 10BF2AB6 5B039796 10B6DDB0 10BF7B70 00000012 0402C541 0402BFD7 10A793DC
Addr: 5B0397A8 10BF2AB6 000001D4 10BF398A 10E67700 10BF298E 10000830 --------
Stck: 000001D4 10A9840E 10BF5B03 97962B00 10BF3906 10B2CFB2 0000003F 10BF2A96
Stck: 10BF2AB6 00000000
Alert !! Alert 81000005 TCB: 10789918 USP: 10BF77A0
Data: 25EBB460 00003010 25EB9441 26019B60 00000012 0402C541 0402BFD7 81000005
Addr: 00003000 0015E700 000A30E8 10A793DC 10E67700 00F9F5BE 10000830 --------
Stck: 00F81D38 10A7750C 10B72AD4 00F81D64 10378574 25EB9441 10A7750C 00000012
----> 00F81D38 - "ROM - exec 40.10 (15.7.93)" Hunk 0000 Offset 00001C7E
----> 00F81D64 - "ROM - exec 40.10 (15.7.93)" Hunk 0000 Offset 00001CAA
----> 10378574 - "LIBS:ixemul.library" Hunk 0000 Offset 00014DE4
Here is MCP'S GuruHistory:
Date : Saturday 07-Jan-12 14:44:23
Task : 10789918 "thttpd"
Error : 81000005 (DEADEND)
By : ExecLibrary
Cause : Corrupt memory list detected in FreeMem
Could anyone help me decipher what is happening please? :help
Toni Wilen
07 January 2012, 21:08
Try to find which locale.library call is causing the error by adding some debug prints.
btw, do you have large enough stack? Unix ports may need huge stacks. (100k+)
tygre
07 January 2012, 22:17
Before I go on adding debug prints, I just would like to confirm that locale.library is the implementation of the functions provided by locale.h, right?
PS. Tried increasing the stack to 200,000, both in WinUAE and on my Classic Amiga, but no luck: still the same kind of "uninitialised trap #0 vector" gurus...
NovaCoder
07 January 2012, 23:00
Here are some more details and a code snippet illustrating my problem:
#include <stdio.h>
int main()
{
printf("Hello World!\n");
void* ptr = malloc(1000);
// realloc(ptr, 10000);
free(ptr);
printf("Goodbye.\n");
return(0);
}
Please, let me know what you think! :help
Tygre
The gcc memory allocation routines seem to be a bit stuffed from what I've seen with calloc. The easiest thing to do is just re-implement relloc if that is what is causing you issues.
With calloc I found that if zero bytes were requested it would return NULL whereas other implementations behave the same way as malloc does when it is asked to allocate zero bytes (eg it doesn't return NULL).
This is the #define I use for the calloc issue:
#if !defined(FORCEINLINE) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define FORCEINLINE inline __attribute__((__always_inline__))
#endif
#ifndef FORCEINLINE
#define FORCEINLINE inline
#endif
// Fix 68k GCC issues with memory allocation/deallocation.
static FORCEINLINE void *callocEx(size_t num, size_t size) {
if (num == 0) {
num = 1;
}
return calloc(num, size);
}
#define calloc(num, size) callocEx(num, size)
tygre
08 January 2012, 02:51
Thanks Novacoder, I will check the calls to calloc in THTTPd (and use your code to replace them :cool) and get inspiration from your code to eventually reimplement realloc.
But before doing that, I will follow Toni's advice and try to locate the call(s) causing all these hits in Enforcer related to locale.library, once step at a time :).
Toni Wilen
08 January 2012, 10:17
With calloc I found that if zero bytes were requested it would return NULL whereas other implementations behave the same way as malloc does when it is asked to allocate zero bytes (eg it doesn't return NULL).
This is not a bug. C library memory allocation routines are allowed to return NULL or non-NULL pointer when attempting to allocate zero bytes. Both are valid return values.
tygre
08 January 2012, 15:21
I located at least one source of Enforcer's hits related to locale.library. PHP includes this piece of code in Zend/zend_compile.c, which is called when declaring a function in PHP:
static void build_runtime_defined_function_key(zval *result, zval *name, zend_op *opline TSRMLS_DC)
{
char lineno_buf[32];
uint lineno_len;
char *filename;
lineno_len = zend_sprintf(lineno_buf, "%d", opline->lineno);
if (CG(active_op_array)->filename) {
filename = CG(active_op_array)->filename;
} else {
filename = "-";
}
/* NULL, name length, filename length, line number length */
result->value.str.len = 1+name->value.str.len+strlen(filename)+lineno_len;
result->value.str.val = (char *) emalloc(result->value.str.len+1);
sprintf(result->value.str.val, "%c%s%s%s", '\0', name->value.str.val, filename, lineno_buf);
result->type = IS_STRING;
result->refcount = 1;
}
I instrumented this piece of code like that:
static void build_runtime_defined_function_key(zval *result, zval *name, zend_op *opline TSRMLS_DC)
{
char lineno_buf[32];
uint lineno_len;
char *filename;
char output[32];
sprintf(output, "\ta.\n");
write(1, output, strlen(output));
lineno_len = zend_sprintf(lineno_buf, "%d", opline->lineno);
sprintf(output, "\tb.\n");
write(1, output, strlen(output));
if (CG(active_op_array)->filename) {
sprintf(output, "\tc.\n");
write(1, output, strlen(output));
filename = CG(active_op_array)->filename;
sprintf(output, "\td.\n");
write(1, output, strlen(output));
} else {
filename = "-";
}
/* NULL, name length, filename length, line number length */
result->value.str.len = 1+name->value.str.len+strlen(filename)+lineno_len;
sprintf(output, "\te.\n");
write(1, output, strlen(output));
result->value.str.val = (char *) emalloc(result->value.str.len+1);
sprintf(output, "\tf.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%c", '\0');
sprintf(output, "\tf1.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%s", name->value.str.val);
sprintf(output, "\tf2.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%c%s", '\0', name->value.str.val);
sprintf(output, "\tf3.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%c%s", 'a', " strange thing...");
sprintf(output, "\tf4.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%c%s", '\0', " strange thing...");
sprintf(output, "\tf5.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%c%s", 'a', name->value.str.val);
sprintf(output, "\tf6.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%s%c", name->value.str.val, '\0');
sprintf(output, "\tf7.\n");
write(1, output, strlen(output));
sprintf(output, "%c%s", '\0', " strange thing...");
sprintf(output, "\tf8.\n");
write(1, output, strlen(output));
sprintf(result->value.str.val, "%c%s%s%s", '\0', name->value.str.val, filename, lineno_buf);
sprintf(output, "\tg.\n");
write(1, output, strlen(output));
result->type = IS_STRING;
result->refcount = 1;
}
And here is the output from the console, in which both Enforcer and THTTPd run and output (copied by hand so I skip some details):
a.
b.
c.
d.
e.
f.
f1.
f2.
BYTE-READ from...
...
----> 10274BDC - "LIBS:locale.library"
Name: "Background CLI" CLI: "thttpd"f3.
f4.
BYTE-READ from...
...
----> 10274BDC - "LIBS:locale.library"
Name: "Background CLI" CLI: "thttpd"f5.
f6.
f7.
BYTE-READ from...
...
----> 10274BDC - "LIBS:locale.library"
Name: "Background CLI" CLI: "thttpd" f8.
BYTE-READ from...
...
----> 10274BDC - "LIBS:locale.library"
Name: "Background CLI" CLI: "thttpd"
BYTE-READ from...
...
----> 10274BDC - "LIBS:locale.library"
Name: "Background CLI" CLI: "thttpd"
BYTE-READ from...
...
----> 10274BDC - "LIBS:locale.library"
Name: "Background CLI" CLI: "thttpd" g.
which means that anytime a call to sprinf is made with "%c" and '\0' as first format and character, there is a hit in the locale.library. Does it make sense?
Also, does it make sense that the following simple code snippet does not produce a hit in Enforcer?
#include <stdio.h>
int main()
{
char output[32];
printf("1.\n");
sprintf(output, "%c%s", '\0', " strange thing...");
printf("2.\n");
sprintf(output, "%s%c", " strange thing...", '\0');
printf("Done.\n");
return(0);
}
What do you think? :)
I found out that I can replace the calls to sprintf with calls to zend_sprintf, which is defined when sprintf is "broken". This replacement yields the expected results and does not produce any hit in Enforcer :cool
#if ZEND_BROKEN_SPRINTF
int zend_sprintf(char *buffer, const char *format, ...)
{
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
return strlen(buffer);
}
#endif
So, should I guess that sprintf is really broken in IXEmul?
Toni Wilen
08 January 2012, 16:46
I think this is GCC variadic function stack parameter size issue which is (was?) problem in m68k AROS too.
GCC always converts all variadic function parameters to LONG. Amiga m68k routines expect WORD unless it has 'l' prefix or parameter is an address.
Quick test: replace %c with %lc. Does it work now?
tygre
08 January 2012, 18:22
You are absolutely right, Toni :cool I replaced the original call:
sprintf(result->value.str.val, "%c%s%s%s", '\0', name->value.str.val, filename, lineno_buf);
which yields to hits in Enforcer, with the call:
sprintf(result->value.str.val, "%lc%s%s%s", '\0', name->value.str.val, filename, lineno_buf);
and the code works like a charm without any hits :) But what a pain to track... and to fix: Toni, does this mismatch between GCC and AmigaOS means that we should systematically add 'l' to any parameter format:
%c -> %lc
%d -> %ld
%e -> %le
...
except if the parameter is a pointer? Actually, what would happen if the parameter is a pointer and we would add 'l'?
Now, its seems that my version of THTTPd works fine, without anymore Enforcer's hit or crash... I will revert the stack to its original size of 40,000 instead of the current 200,000 to see if I can reproduce my original crash, count on me to keep you posted ;) Thanks a lot for your kind help!
NovaCoder
09 January 2012, 04:32
This is not a bug. C library memory allocation routines are allowed to return NULL or non-NULL pointer when attempting to allocate zero bytes. Both are valid return values.
That may be true but for the large (multi-plaform) C++ project that I'm building (ScummVM), only the 68k version of gcc seems to behave this way :sad
Toni Wilen
09 January 2012, 11:12
and the code works like a charm without any hits :) But what a pain to track... and to fix: Toni, does this mismatch between GCC and AmigaOS means that we should systematically add 'l' to any parameter format:
%c -> %lc
%d -> %ld
%e -> %le
...
Yeah, that works but perhaps there is better solution.
except if the parameter is a pointer? Actually, what would happen if the parameter is a pointer and we would add 'l'?
Nothing happens but it would look even more ugly :)
Now, its seems that my version of THTTPd works fine, without anymore Enforcer's hit or crash... I will revert the stack to its original size of 40,000 instead of the current 200,000 to see if I can reproduce my original crash, count on me to keep you posted ;) Thanks a lot for your kind help!
Great!
That may be true but for the large (multi-plaform) C++ project that I'm building (ScummVM), only the 68k version of gcc seems to behave this way :sad
It still is not a bug, not even if it returns NULL on thursdays and non-NULL on other days :D
I thought most bigger projects would use some kind of memory allocation wrapper(s) for portability reasons.
tygre
09 January 2012, 15:19
Thanks a lot Toni!
A solution could be to wrap any call to the [sn]printf family of functions so that the wrapper could automagically add 'l' in front of each format character... I guess scanf could have the same problem?
When I succeed in reproducing this behaviour, I'll try and keep you posted!
BTW, my apologies for saying that IXEmul was broken, it is not :cool
tygre
12 January 2012, 03:12
PS. Dear moderators, would it be possible to add "[Solved]" :) to the title of this thread? Thanks!
prowler
12 January 2012, 21:36
PS. Dear moderators, would it be possible to add "[Solved]" :) to the title of this thread? Thanks!
Done! :great
tygre
12 February 2012, 18:14
PS. Thanks Prowler!
PPS. THTTPd "starts" crashing again. I must have missed some sprintf... I am tracking them down (http://eab.abime.net/showthread.php?p=801923) now... It is my mistake, I mean: the solution in this thread works! :)
vBulletin® v3.7.0, Copyright ©2000-2013, Jelsoft Enterprises Ltd.