22 May, 2012, Tyche wrote in the 1st comment:
Votes: 0
I just finished porting, well re-porting, CoolMud 2.2.1 again.
You can find it in the Tiny area of the code repository.

However I can across a runtime bug that shows up only when using gcc 4.x compilers. The code works perfectly
under gcc 3.x, Digital Mars, Borland 5.5 and 6.3, and all versions of Visual C from v6.0 to the new beta 2011.
I was unable to figure it out, but I was able to work around it.

The problem is this. CoolMud has it's own mud programming language which compiles to byte code which runs
on a virtual machine. The CoolMud compiler spits out an invalid code under certain conditions with gcc4 regardless of
whether I'm using yacc, byacc, or bison.

Here's an example. You can dump the bytecode of methods inside the mud using the @spew command.
Server compiled with gcc 3.3
@spew init on #7
THIS OBJPUSH 7 0 EQ IF 17 81 THIS OBJPUSH 11 0 MESSAGE 1 "add_owner" POP STOP CALLER THIS EQ OR 26 CALLER GETGVAR owners IN ENDOR OR 32 CALLER PARENTS IN ENDOR OR 40 CALLER OBJPUSH 0 0 EQ ENDOR OR 51 CALLER OBJPUSH 0 0 MESSAGE 0 "wizards" IN ENDOR OR 57 GETGVAR owners NOT ENDOR ELSEIF 75 OBJPUSH -1 0 ASGNGVAR source OBJPUSH -1 0 ASGNGVAR dest PASS 0 3 POP STOP ELSE ERRPUSH 10 RAISE STOP STOP STOP

Server compiled with gcc 4.4.1
@spew init on #7
THIS OBJPUSH 7 0 EQ IF 17 81 THIS OBJPUSH 11 0 MESSAGE 1 "add_owner" POP STOP CALLER THIS EQ OR 26 CALLER GETGVAR owners IN ENDOR OR 0 CALLER PARENTS IN ENDOR OR 40 CALLER OBJPUSH 0 0 EQ ENDOR OR 51 CALLER OBJPUSH 0 0 MESSAGE 0 "wizards" IN ENDOR OR 57 GETGVAR owners NOT ENDOR ELSEIF 75 OBJPUSH -1 0 ASGNGVAR source OBJPUSH -1 0 ASGNGVAR dest PASS 0 3 POP STOP ELSE ERRPUSH 10 RAISE STOP STOP STOP

Note how the instruction following the OR instruction is a 0 with gcc4 but with gcc3 is a 32, which is correct.
The instruction following the OR is a jump address relative to start of the bytecode. It is filled in with the address
of the next ENDOR operand at the time the ENDOR opcode is encountered.

The same error occurs with the AND opcode on object #7 method match.
@spew match on #7 to see it.

Here's the generated parser code from YACC with my comments:
case 124:
#line 392 "src/cool.y"
{ yyval.num = code2(AND, 0); }
break;
case 125:
#line 393 "src/cool.y"
{ machine[yyvsp[-1].num + 1] = code(ENDAND); // This writes the location of ENDAND to the byte following AND
yyval.num = yyvsp[-3].num; }
break;
case 126:
#line 395 "src/cool.y"
{ yyval.num = code2(OR, 0); }
break;
case 127:
#line 396 "src/cool.y"
{ machine[yyvsp[-1].num + 1] = code(ENDOR); // This writes the location of ENDOR to the byte following OR
yyval.num = yyvsp[-3].num; }
break;

ENDOR and ENDAND are null opcodes. The purpose is to jump to process the next boolean expression.

In all cases this happens when the jump location is exactly 32. 32 happens to be the initial size allocated
to the virtual machine, and it reallocates a double amount each time you run out of room.

Here's a link to the repository code that allocates the virtual machine.
http://sourcery.dyndns.org/svn/coolmud/t...

I've looked, traced, set watches and looked again and I just can't find the problem.

My workaround was to change CODE_INIT_SIZE to 4096 from 32. If I do that the problem disappears, but I suspect
would reappear if the method generated a large amount of bytecode.

The really really odd thing is there are no compiler warnings in regards to this and it works in every other compiler save gcc 4.x.
And this happens with both 32-bit and 64-bit gcc 4.x compilers on Cygwin and on native Linuxes.

Any ideas?
22 May, 2012, Vigud wrote in the 2nd comment:
Votes: 0
[me@localhost coolmud]$ grep 'CODE_INIT_SIZE' src/cool.h
#define CODE_INIT_SIZE 32
[me@localhost coolmud]$ gcc -v 2>&1 | grep version
gcc version 4.6.3 20120306 (Red Hat 4.6.3-2) (GCC)
[me@localhost coolmud]$ make
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/ndbm/hash.c -osrc/ndbm/hash.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/ndbm/hash_bigkey.c -osrc/ndbm/hash_bigkey.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/ndbm/hash_buf.c -osrc/ndbm/hash_buf.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/ndbm/hash_func.c -osrc/ndbm/hash_func.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/ndbm/hash_log2.c -osrc/ndbm/hash_log2.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/ndbm/hash_page.c -osrc/ndbm/hash_page.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/ndbm/ndbm.c -osrc/ndbm/ndbm.o
ar rsc src/ndbm/libndbm.a src/ndbm/hash.o src/ndbm/hash_bigkey.o src/ndbm/hash_buf.o src/ndbm/hash_func.o src/ndbm/hash_log2.o src/ndbm/hash_page.o src/ndbm/ndbm.o
byacc -l -d src/cool.y
byacc: 2 shift/reduce conflicts.
mv y.tab.c src/cool.c
mv y.tab.h src/y.tab.h
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/cool.c -osrc/cool.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/perms.c -osrc/perms.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/error.c -osrc/error.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/code.c -osrc/code.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/symbol.c -osrc/symbol.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/utils.c -osrc/utils.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/decode.c -osrc/decode.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/list.c -osrc/list.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/map.c -osrc/map.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/var.c -osrc/var.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/verb.c -osrc/verb.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/method.c -osrc/method.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/compile.c -osrc/compile.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/execute.c -osrc/execute.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/opcode.c -osrc/opcode.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/opcodes1.c -osrc/opcodes1.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/opcodes2.c -osrc/opcodes2.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/opcodes3.c -osrc/opcodes3.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/builtins.c -osrc/builtins.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/servers.c -osrc/servers.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/dispatch.c -osrc/dispatch.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/message.c -osrc/message.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/storage.c -osrc/storage.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/dbsize.c -osrc/dbsize.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/dbpack.c -osrc/dbpack.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/dbunpack.c -osrc/dbunpack.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/hash.c -osrc/hash.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/string.c -osrc/string.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/buf.c -osrc/buf.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/netio.c -osrc/netio.o
src/netio.c: In function server_input:
src/netio.c:311:5: warning: pointer targets in passing argument 6 of recvfrom differ in signedness [-Wpointer-sign]
/usr/include/sys/socket.h:166:16: note: expected socklen_t * __restrict__ but argument is of type int *
src/netio.c: In function new_player:
src/netio.c:327:40: warning: pointer targets in passing argument 3 of accept differ in signedness [-Wpointer-sign]
/usr/include/sys/socket.h:214:12: note: expected socklen_t * __restrict__ but argument is of type int *
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/playerio.c -osrc/playerio.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/serverio.c -osrc/serverio.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/cache.c -osrc/cache.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/dbmchunk.c -osrc/dbmchunk.o
gcc -c -O2 -fno-strict-aliasing -Wall -Wextra -Wno-parentheses -Wno-unused -g -Isrc/ndbm src/os.c -osrc/os.o
gcc -O2 -fno-strict-aliasing -g -obin/cm.exe src/ndbm/libndbm.a src/cool.o src/perms.o src/error.o src/code.o src/symbol.o src/utils.o src/decode.o src/list.o src/map.o src/var.o src/verb.o src/method.o src/compile.o src/execute.o src/opcode.o src/opcodes1.o src/opcodes2.o src/opcodes3.o src/builtins.o src/servers.o src/dispatch.o src/message.o src/storage.o src/dbsize.o src/dbpack.o src/dbunpack.o src/hash.o src/string.o src/buf.o src/netio.o src/playerio.o src/serverio.o src/cache.o src/dbmchunk.o src/os.o -Lsrc/ndbm -lcrypt -lndbm
rm -f west.tmp
for file in bin/root_obj.cl bin/sys_obj.cl bin/located_obj.cl bin/described_obj.cl bin/thing.cl bin/container.cl bin/room.cl bin/exit.cl bin/player.cl bin/builder.cl bin/programmer.cl bin/wizard.cl bin/west.cl; do gcc -E -P -x c $file >> west.tmp; done
bin/cm.exe bin/west -i -f west.tmp
May 22 22:07:51: Reading config file from bin/west.cfg
May 22 22:07:51: Cache depth starts at 23 slots.
May 22 22:07:51: Cache width is 7 slots.
May 22 22:07:51: Initializing db
May 22 22:07:51: Initializing cache
May 22 22:07:51: SYS_OBJ: #0 not found
May 22 22:07:51: SYS_OBJ: #0 not found
Object #1 programmed.
Object #0 programmed.
Object #2 programmed.
Object #3 programmed.
Object #4 programmed.
Object #5 programmed.
Object #6 programmed.
Object #7 programmed.
Object #8 programmed.
Object #9 programmed.
Object #10 programmed.
Object #11 programmed.
Object #12 programmed.
Object #13 programmed.
Object #14 programmed.
Object #15 programmed.
May 22 22:07:51: Syncing cache
May 22 22:07:51: Closing database
rm -f west.tmp
rm -f east.tmp
for file in bin/root_obj.cl bin/sys_obj.cl bin/located_obj.cl bin/described_obj.cl bin/thing.cl bin/container.cl bin/room.cl bin/exit.cl bin/player.cl bin/builder.cl bin/programmer.cl bin/wizard.cl bin/east.cl; do gcc -E -P -x c $file >> east.tmp; done
bin/cm.exe bin/east -i -f east.tmp
May 22 22:07:51: Reading config file from bin/east.cfg
May 22 22:07:51: Cache depth starts at 23 slots.
May 22 22:07:51: Cache width is 7 slots.
May 22 22:07:51: Initializing db
May 22 22:07:51: Initializing cache
May 22 22:07:51: SYS_OBJ: #0 not found
May 22 22:07:51: SYS_OBJ: #0 not found
Object #1 programmed.
Object #0 programmed.
Object #2 programmed.
Object #3 programmed.
Object #4 programmed.
Object #5 programmed.
Object #6 programmed.
Object #7 programmed.
Object #8 programmed.
Object #9 programmed.
Object #10 programmed.
Object #11 programmed.
Object #12 programmed.
Object #13 programmed.
Object #14 programmed.
May 22 22:07:51: Syncing cache
May 22 22:07:51: Closing database
rm -f east.tmp
[me@localhost coolmud]$ cd bin
[me@localhost bin]$ ./cm.exe west &
[1] 12432
[me@localhost bin]$ May 22 22:07:59: Reading config file from west.cfg
May 22 22:07:59: Cache depth starts at 23 slots.
May 22 22:07:59: Cache width is 7 slots.
May 22 22:07:59: Initializing db
May 22 22:07:59: Initializing cache
May 22 22:07:59: Initializing sockets.
May 22 22:07:59: Connecting to remote servers.
May 22 22:07:59: Server initialized.
telnet 0 7777
Trying 0.0.0.0…
Connected to 0.
May 22 22:08:06: Escape character is '^]'.
Accepted player from 127.0.0.1(-24871)


*** WELCOME TO COOLMUD WEST! ***

COOLMUD created by Stephen White.

Use "create <name> <password>" to create a new character.
Use "connect <name> <password>" to connect to an existing character.

create new character
May 22 22:08:10: Player created: new(#16) on descriptor 7
*** Connected ***
You're absolutely nowhere. Go home.
@spew init on #7
THIS OBJPUSH 7 0 EQ IF 17 81 THIS OBJPUSH 11 0 MESSAGE 1 "add_owner" POP STOP CALLER THIS EQ OR 26 CALLER GETGVAR owners IN ENDOR OR 0 CALLER PARENTS IN ENDOR OR 40 CALLER OBJPUSH 0 0 EQ ENDOR OR 51 CALLER OBJPUSH 0 0 MESSAGE 0 "wizards" IN ENDOR OR 57 GETGVAR owners NOT ENDOR ELSEIF 75 OBJPUSH -1 0 ASGNGVAR source OBJPUSH -1 0 ASGNGVAR dest PASS 0 3 POP STOP ELSE ERRPUSH 10 RAISE STOP STOP STOP


Every thing the same, except clang instead of gcc: @spew init on #7
THIS OBJPUSH 7 0 EQ IF 17 81 THIS OBJPUSH 11 0 MESSAGE 1 "add_owner" POP STOP CALLER THIS EQ OR 26 CALLER GETGVAR owners IN ENDOR OR 32 CALLER PARENTS IN ENDOR OR 40 CALLER OBJPUSH 0 0 EQ ENDOR OR 51 CALLER OBJPUSH 0 0 MESSAGE 0 "wizards" IN ENDOR OR 57 GETGVAR owners NOT ENDOR ELSEIF 75 OBJPUSH -1 0 ASGNGVAR source OBJPUSH -1 0 ASGNGVAR dest PASS 0 3 POP STOP ELSE ERRPUSH 10 RAISE STOP STOP STOP
23 May, 2012, Tyche wrote in the 3rd comment:
Votes: 0
So it does work with clang. :-)

I tried different optimization switches in gcc-4 to no avail.
I tried to isolate the code in its own world, but the issue disappears.
http://www.mudbytes.net/index.php?a=past...

Which leads me to look at the left hand side of…
{ machine[yyvsp[-1].num + 1] = code(ENDOR);  // This writes the location of ENDOR to the byte following OR


code() changes the address of machine when it allocates a bigger one.
So it's like the left hand side of the above still points to the old machine.

I wonder if there's some ambiguity in the C standard that the code is relying on.
23 May, 2012, Tyche wrote in the 4th comment:
Votes: 0
Here we go. This bit of code illustrates the problem, without all the server cruft.

#include <stdlib.h>
#include <stdio.h>

#define CODE_INIT_SIZE 32

int *machine;
int progi, machine_size;

void code_init (void)
{
machine_size = CODE_INIT_SIZE;
machine = (int*) malloc (sizeof(int) * machine_size);
progi = 0;
}

int code (int inst)
{
int *new_machine;
int i;

if (!machine || !machine_size) {
code_init ();
}
if (progi >= machine_size) {
machine_size *= 2;
new_machine = (int*) malloc (sizeof(int) * machine_size);
for (i = 0; i < progi; i++) {
new_machine[i] = machine[i];
}
free (machine);
machine = new_machine;
}
machine[progi++] = inst;
return progi - 1;
}

int main() {
int i;
code(0);
for (i=0;i<100;i++) {
if (i<30)
machine[i] = 0;
else
machine[i-30] = code(0);
}
for (i=0;i<100;i++)
printf("%d ", machine[i]);
return 0;
}


Under gcc 3.x
$ gcc-3 testcode.c
$ ./a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Under gcc 4.x
$ gcc-4 testcode.c
$ ./a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 0 65 66 67 68 69 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
23 May, 2012, Tyche wrote in the 5th comment:
Votes: 0
An even shorter and more drastic illustration using a bunch of different compilers:

#include <stdlib.h>
#include <stdio.h>

int* bar;
int foo ()
{
bar = (int*) malloc (sizeof(int) * 10);
return 99;
}

int main() {
bar[0] = foo();
printf("%d ", bar[0]);
return 0;
}


$ gcc-3 testcode2.c
$ ./a
99


$ gcc-4 testcode2.c
$ ./a
Segmentation fault (core dumped)


>bcc32 testcode2.c
Embarcadero C++ 6.30 for Win32 Copyright © 1993-2010 Embarcadero Technologies, Inc.
testcode2.c:
Warning W8065 testcode2.c 12: Call to function 'foo' with no prototype in function main
Turbo Incremental Link 6.10 Copyright © 1997-2010 Embarcadero Technologies, Inc.
>testcode2
99


>bcc32 testcode2.c
Borland C++ 5.5.1 for Win32 Copyright © 1993, 2000 Borland
testcode2.c:
Warning W8065 testcode2.c 12: Call to function 'foo' with no prototype in function main
Turbo Incremental Link 5.00 Copyright © 1997, 2000 Borland
>testcode2
99


>cl testcode2.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
testcode2.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
/out:testcode2.exe
testcode2.obj
>testcode2
99


>cl testcode2.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
testcode2.c
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
/out:testcode2.exe
testcode2.obj
>testcode2
99


>dmc testcode2
Digital Mars Compiler Version 8.42n
Copyright (C) Digital Mars 2000-2004. All Rights Reserved.
link testcode2,,,user32+kernel32/noi;
>testcode2
99


>lcc -v
Logiciels/Informatique lcc-win32 version 3.8. Compilation date: Nov 24 2011 14:39:47
>lcc testcode2.c
Warning testcode2.c: 12 Missing prototype for 'foo'
0 errors, 1 warning
>testcode2
99
23 May, 2012, Vigud wrote in the 6th comment:
Votes: 0
My post was a mess. I wanted to include the following information: my gcc version, my use of -O0, the output and comparison to another compiler. I posted three logs in total, every one of them was missing a piece of information :)

I will be testing it further this evening, this time I hope to not screw it up.
23 May, 2012, Vigud wrote in the 7th comment:
Votes: 0
int balloons = 77;
int *bar;

int foo( void );

int foo( void )
{
bar = &balloons;
return 99;
}

int main( void )
{
*bar = foo( );
return *bar;
}
Kate from ##C helped me to strip it down to this test-case.
23 May, 2012, Vigud wrote in the 8th comment:
Votes: 0
It's because of the order of evaluation of operands. Try this:

#include <stdlib.h>
#include <stdio.h>
int* bar;
int foo ()
{
bar = (int*) malloc (sizeof(int) * 10);
return 99;
}
int main() {
int temp = foo();
bar[0] = temp;
printf("%d ", bar[0]);
return 0;
}
I don't know whether it's the compiler violating the standard or the code relies on unspecified/undefined behavior. One thing is solved, I believe: it can be circumvented as shown above.
23 May, 2012, Vigud wrote in the 9th comment:
Votes: 0
For the reference:
FreeBSD 9.0-STABLE i386
gcc 4.2, 4.6, 4.7 - segmentation fault
gcc 3.4, clang - works as expected.

Plus this excerpt from C99 draft. I hope it's relevant, because I can hardly understand what it should mean in practice.

Quote
3 An assignment operator stores a value in the object designated by the left operand. An
assignment expression has the value of the left operand after the assignment, but is not an
lvalue. The type of an assignment expression is the type of the left operand unless the
left operand has qualified type, in which case it is the unqualified version of the type of
the left operand. The side effect of updating the stored value of the left operand shall
occur between the previous and the next sequence point.
4 The order of evaluation of the operands is unspecified. If an attempt is made to modify
the result of an assignment operator or to access it after the next sequence point, the
behavior is undefined.
25 May, 2012, Tyche wrote in the 10th comment:
Votes: 0
Quote
It's because of the order of evaluation of operands. Try this:
int temp = foo();
bar[0] = temp;

Thanks. That's the solution I'll implement.
25 May, 2012, Newt wrote in the 11th comment:
Votes: 0
why not just:

bar[0] = (int) foo();


or did I miss something?
25 May, 2012, Vigud wrote in the 12th comment:
Votes: 0
You don't have to cast foo() to int, since it already returns int. And that brings us back to the problem, which comes from the fact that compilers are free to decide whether the return value of foo() should be written to the object that bar was pointing to before or after foo() is called.
0.0/12