In the Macintosh Pascal mailing list (http://pascal-central.com/maillist.html) Scott Lindhurst wrote:
I just started playing around with gpc, working on getting some old code to work with it, and have found a bug. This is version 3.3.2d1, just downloaded a few days ago with the accompanying GPCInterfacesB2, on OS X 10.2.8.
I get the message "gpc: Internal error: Illegal instruction (program gpc1)" when compiling the following program:
program bug;
uses GPCMacOSAll, GPCStringsAll; {No error if remove GPCStringsAll}
var tix: UInt32; {No error if change to integer or longint} begin tix := 1;
if tix > TickCount then {error while processing this line} tix := 2; end.
My makefile generates this command line (which is going to be wrapped, sorry): gpc --automake --unit-path=./:/Developer/Pascal/GPCPInterfaces/ --object-path=./build/ --unit-destination-path=./build/ --executable-path=./build/ -Wl,-framework,Carbon,-framework,ApplicationServices -o ./bug -Wl,-x -O2 -Wall -Wno-identifier-case --ignore-garbage-after-dot --longjmp-all-nonlocal-labels ./bug.pas
but the internal error can be reproduced with just gpc --unit-path=/Developer/Pascal/GPCPInterfaces/ ./bug.pas
I have the workaround of using integer or longint instead of UInt32.
Peter N. Lewis helped out by noting that "limit stacksize 8096" solves the problem. This is true, but still it is strange that the compiler needs such a huge amount of stack for compilation. So, I wonder if maybe there is indeed a problem in the compiler, solved only "by accident" by a stacklimit of nearly a megabyte.
When I set "limit stacksize 4096", the backtrace reads:
Date/Time: 2003-11-07 11:36:46 +0100 OS Version: 10.2.8 (Build 6R73) Host: G4.local.
Command: gpc1 PID: 437
Exception: EXC_BAD_ACCESS (0x0001) Codes: KERN_INVALID_ADDRESS (0x0001) at 0xbff7fff0
Thread 0 Crashed: #0 0x000a9dc8 in tree_size (tree.c:161) #1 0x000aa024 in make_node (tree.c:237) #2 0x000c6980 in alloc_node (stringpool.c:70) #3 0x0024b4b0 in ht_lookup (hashtable.c:162) #4 0x000c6b1c in get_identifier (stringpool.c:109) #5 0x0001bb04 in get_operator (expressions.c:425) #6 0x0001c7e4 in build_pascal_binary_op (expressions.c:661) #7 0x0001c514 in parser_build_binary_op (expressions.c:583) #8 0x0000dd48 in yyuserAction (parse.c:4580) #9 0x000136c8 in yydoAction (parse.c:8238) #10 0x00013190 in yyglrReduce (parse.c:8290) #11 0x000124d0 in main_yyparse (parse.c:8991) #12 0x000a49c0 in compile_file (toplev.c:2134) #13 0x000a9c38 in do_compile (toplev.c:5402) #14 0x000a9d04 in toplev_main (toplev.c:5432) #15 0x00001fa8 in _start (crt.c:267) #16 0x00001e28 in start
PPC Thread State: srr0: 0x000a9dc8 srr1: 0x0200f930 vrsave: 0x00000000 xer: 0x20000000 lr: 0x000a9dc0 ctr: 0x000c6968 mq: 0x00000000 r0: 0x000aa024 r1: 0xbff80040 r2: 0x6c616773 r3: 0xbff80080 r4: 0x0000002a r5: 0x0000002a r6: 0x00000001 r7: 0x00000002 r8: 0x727900e4 r9: 0x002e8a28 r10: 0x02a4f000 r11: 0x00020000 r12: 0x48042447 r13: 0x00000000 r14: 0x00000000 r15: 0x00000000 r16: 0x00000000 r17: 0x00000000 r18: 0x00387e40 r19: 0x002eb814 r20: 0x00000000 r21: 0x00000001 r22: 0xbff80200 r23: 0x0000002a r24: 0x0000b04b r25: 0xe972469b r26: 0x00883890 r27: 0x00000078 r28: 0x00000000 r29: 0x00011a6c r30: 0x00000001 r31: 0x000a9dc0
[G4:~] adriaan% gpc -v Reading specs from /Developer/Pascal/gpc332d1/lib/gcc-lib/powerpc-apple-darwin/3.3.2/specs Configured with: ../gpc-332d1/configure --enable-languages=pascal,c --prefix=/Developer/Pascal/gpc332d1 --enable-threads=posix --target=powerpc-apple-darwin Thread model: posix gpc version 20030830, based on gcc-3.3.2
The same problem also occurs with the previous alpha and gcc-3.3, but the backtrace is different:
Date/Time: 2003-11-07 11:34:03 +0100 OS Version: 10.2.8 (Build 6R73) Host: G4.local.
Command: gpc1 PID: 404
Exception: EXC_BAD_ACCESS (0x0001) Codes: KERN_INVALID_ADDRESS (0x0001) at 0xbff7ffe0
Thread 0 Crashed: #0 0x000c3b74 in alloc_page (ggc-page.c:660) #1 0x000c2b24 in ggc_alloc (ggc-page.c:1026) #2 0x0009c430 in make_node (tree.c:292) #3 0x000c25ac in alloc_node (stringpool.c:70) #4 0x0023cd30 in ht_lookup (hashtable.c:161) #5 0x000c2748 in get_identifier (stringpool.c:109) #6 0x000097d4 in get_operator (expressions.c:426) #7 0x0000a478 in build_pascal_binary_op (expressions.c:656) #8 0x0000a1ac in parser_build_binary_op (expressions.c:578) #9 0x0002d8d8 in main_yyparse (parse.c:2400) #10 0x00096e88 in compile_file (toplev.c:2134) #11 0x0009c03c in do_compile (toplev.c:5370) #12 0x0009c108 in toplev_main (toplev.c:5400) #13 0x000018a8 in _start (crt.c:267) #14 0x00001728 in start
PPC Thread State: srr0: 0x000c3b74 srr1: 0x0000f930 vrsave: 0x00000000 xer: 0x00000000 lr: 0x000c3b6c ctr: 0x0009c3a0 mq: 0x00000000 r0: 0x000c2b24 r1: 0xbff80060 r2: 0x6c616773 r3: 0x00000023 r4: 0xbff80280 r5: 0x00000027 r6: 0x00000000 r7: 0x00000003 r8: 0xbff80100 r9: 0x002db53c r10: 0x00000001 r11: 0x0000002c r12: 0x88048444 r13: 0x00000003 r14: 0x000000c8 r15: 0xbfffec80 r16: 0x00000034 r17: 0x00000000 r18: 0x0036c9a0 r19: 0x002d94e4 r20: 0x00000000 r21: 0x02fa3e70 r22: 0x00000001 r23: 0xbff80280 r24: 0x00302ad0 r25: 0x00302ad0 r26: 0x00824890 r27: 0x0000008c r28: 0x03423e70 r29: 0x0000002c r30: 0x002fc69c r31: 0x000c3b6c
The needed units can be found at <www.microbizz.nl/GPCMacOSAll.pas.bz2> and <www.microbizz.nl/GPCStringsAll.pas.bz2>. They were too large to include with this message.
Regards,
Adriaan van Os
Adriaan van Os wrote:
In the Macintosh Pascal mailing list (http://pascal-central.com/maillist.html) Scott Lindhurst wrote:
I just started playing around with gpc, working on getting some old code to work with it, and have found a bug. This is version 3.3.2d1, just downloaded a few days ago with the accompanying GPCInterfacesB2, on OS X 10.2.8.
I get the message "gpc: Internal error: Illegal instruction (program gpc1)" when compiling the following program:
program bug;
uses GPCMacOSAll, GPCStringsAll; {No error if remove GPCStringsAll}
var tix: UInt32; {No error if change to integer or longint} begin tix := 1;
if tix > TickCount then {error while processing this line} tix := 2; end.
<snip>
but the internal error can be reproduced with just gpc --unit-path=/Developer/Pascal/GPCPInterfaces/ ./bug.pas
I have the workaround of using integer or longint instead of UInt32.
Peter N. Lewis helped out by noting that "limit stacksize 8096" solves the problem. This is true, but still it is strange that the compiler needs such a huge amount of stack for compilation. So, I wonder if maybe there is indeed a problem in the compiler, solved only "by accident" by a stacklimit of nearly a megabyte.
I fetched the units and tried on i386. Appearently, running on i386 Linux, the compiler needs 4272 kB (more then four megabytes) to compile the program. AFAIKS the file GPCMacOSAll defines more then 270 variants of the UInt32 type. In the function `get_operator' the compiler performs quadratic search for comparison operator (checking _all_ pairs of variants of UInt32 type). For each pairs of variants the compiler generates appropriate name for possible comparison operator and checks if it is present. The names are allocated on the stack and accumulate.
If looks easy to avoid accumulating names on the stack, but the quadratic search makes the compiler quite slow (at least with your types...).
Waldek Hebisch wrote:
I fetched the units and tried on i386. Appearently, running on i386 Linux, the compiler needs 4272 kB (more then four megabytes) to compile the program. AFAIKS the file GPCMacOSAll defines more then 270 variants of the UInt32 type. In the function `get_operator' the compiler performs quadratic search for comparison operator (checking _all_ pairs of variants of UInt32 type). For each pairs of variants the compiler generates appropriate name for possible comparison operator and checks if it is present. The names are allocated on the stack and accumulate.
If looks easy to avoid accumulating names on the stack, but the quadratic search makes the compiler quite slow (at least with your types...).
Basically, the whole operator overloading is a big kludge. I'd have liked to throw it all out, unfortunately there are some who need it ...
Someday it should be reimplemented, but currently it's not very urgent to me.
The attached patch avoids accumulating names on the stack, so it will hopefully solve the memory problem, but not make the compiler faster.
BTW, I'm wondering what these files actually do. GPCStringsAll defines 216 operators for `+' and relations for various string types. GPC has those operations built-in already and they work with any string type (not just the selection defined here)? Also, GPC allows assignments between string types, so the `StrXX[In]ToStrYY' routines are redundant.
I remember we (i.e., Peter N Lewis and me) talked about such operators for "emulating" short strings last year. But this unit uses the regular GPC string types, so it all seems quite pointless to me.
Frank
Frank Heckenbach wrote:
BTW, I'm wondering what these files actually do. GPCStringsAll defines 216 operators for `+' and relations for various string types. GPC has those operations built-in already and they work with any string type (not just the selection defined here)? Also, GPC allows assignments between string types, so the `StrXX[In]ToStrYY' routines are redundant.
I remember we (i.e., Peter N Lewis and me) talked about such operators for "emulating" short strings last year. But this unit uses the regular GPC string types, so it all seems quite pointless to me.
Frank, I think you missed something in your examination of the GPCStringsAll unit. It actually is a helper/glue unit for emulating short strings along with support for copying to and from GPC's native schema based strings and packed array of char with length byte short strings.
Although it doesn't cover every possible short string size, it does cover those sizes needed to call the Apple defined Mac OS interface routines. All the StrXX types are short string types and the type declarations for those can be found in MacTypes.pas (they are also in the gigantic, include everything GPCMacOSAll.pas). The StringXX types are GPC native string types with capacities set to match the maximum length capability of the corresponding StrXX type.
For an example, the Str15 "short string" type is declared in MacTypes.pas (and also GPCMacOSAll.pas) as:
Str15 = record sLength: Byte; sChars: packed array[1..15] of char; end;
and the String15 "GPC string" type is declared in GPCStringsAll.pas as:
String15 = String(15);
The code in GPCStringsAll.pas does exploit GPC's support for Extended Pascal's substring function access for copying the fixed string sChars field of the "short string" record which may give the impression that it is just duplicating what GPC already provides. However, a closer inspection will reveal that there is additional code to handle the sLength field of the "short string" record which GPC doesn't have any built-in support for. In particular, `StrXX[In]ToStrYY' routines which you think are redundant aren't redundant since those routines have the additioal code needed to correctly set the sLength field of the "short string" record.
Gale Paeper gpaeper@empirenet.com
Gale Paeper wrote:
Frank, I think you missed something in your examination of the GPCStringsAll unit. It actually is a helper/glue unit for emulating short strings along with support for copying to and from GPC's native schema based strings and packed array of char with length byte short strings.
[...]
Ah OK, I was just confused by the fact that the unit declares `StringXX' types and then goes on to define operators using (mostly) `StrXX' which looks similar enough to overlook the difference without a helping comment ...
Frank
Frank Heckenbach wrote:
Waldek Hebisch wrote:
I fetched the units and tried on i386. Appearently, running on i386 Linux, the compiler needs 4272 kB (more then four megabytes) to compile the program. AFAIKS the file GPCMacOSAll defines more then 270 variants of the UInt32 type. In the function `get_operator' the compiler performs quadratic search for comparison operator (checking _all_ pairs of variants of UInt32 type). For each pairs of variants the compiler generates appropriate name for possible comparison operator and checks if it is present. The names are allocated on the stack and accumulate.
If looks easy to avoid accumulating names on the stack, but the quadratic search makes the compiler quite slow (at least with your types...).
Basically, the whole operator overloading is a big kludge. I'd have liked to throw it all out, unfortunately there are some who need it ...
Someday it should be reimplemented, but currently it's not very urgent to me.
AFAIKS the current implementation is against the standard spirit. Namely, according to the standard declaration:
type typea = typeb;
merely introduces new name for `typeb'. And in all other places what matters is the type. To obey this spirit operators should use types, which will eliminate the whole quadratic seach completely. We do have a problem: GPC currently has problems tracking type equality, but fixing type handling should have (IMHO) very high priority.
I think that type and operator handling can be fixed with quite moderate effort. Of course, that would break users of old semantic, who use alternate type name to trigger different operator :(.
Waldek Hebisch wrote:
Basically, the whole operator overloading is a big kludge. I'd have liked to throw it all out, unfortunately there are some who need it ...
Someday it should be reimplemented, but currently it's not very urgent to me.
AFAIKS the current implementation is against the standard spirit.
AFAIK, the only standard (more or less) that has operator overloading is PXSC. I don't know it in detail. If someone here happens to know about it, please let us know ...
Namely, according to the standard declaration:
type typea = typeb;
merely introduces new name for `typeb'. And in all other places what matters is the type. To obey this spirit operators should use types, which will eliminate the whole quadratic seach completely.
Yes, that's my idea to reimplement it. There are some questions left, though:
- Should exact matching or only assignment compatibility be required (for value parameters)? The latter would seem logical to me.
- What if several operators match, should this be an error? (If so, it would not be possible to, e.g., define the same operator for Integer and LongInt. If not, it might be difficult to specify exactly which operator is used.)
- What if a user-defined operator conflicts with a built-in one? Should this be an error, or should the user-defined one always take precedence?
- ...
I think that type and operator handling can be fixed with quite moderate effort. Of course, that would break users of old semantic, who use alternate type name to trigger different operator :(.
Is there anybody here who requires this? (Just at attempt ... ;-)
I think it can always be worked around by creating a really new type (e.g., a record with one field), which would seem cleaner to me, too.
Frank