On Mon, Feb 21, 2005 at 03:37:13PM +0100, Waldek Hebisch wrote:
Emil Jerabek wrote:
TEST baby.pas: ./a.out: value out of range (error #300 at 804d70a)
Which means:
The patch works.
Failures of awindtes* and dostest* also went away.
As for baby.pas: I found meanwhile that it is the same problem which
I reported in another mail, i.e., inability to allocate more than about 128kB of memory. The offending range check happens after the increment in AddHeapRange in rts/heap.pas:
procedure AddHeapRange (p: Pointer; Size: SizeType); var Address: PtrCard; begin Address := PtrCard (p); if (HeapLow = 0) or (Address < HeapLow) then HeapLow := Address; Inc (Address, Size - 1);
^^^^
if Address > HeapHigh then HeapHigh := Address end;
Disassembling the code reveals:
0x0804ef0f <AddHeapRange+31>: lea 0xffffffff(%eax,%edx,1),%eax 0x0804ef13 <AddHeapRange+35>: test %eax,%eax 0x0804ef15 <AddHeapRange+37>: js 0x804ef26 <AddHeapRange+54> ^^^^^^
Unfortunatly, this is correct translation of the above line according to current rules: 1 is of type integer (so it is considerd signed). Currently substractiong or adding Integer to Carginal gives Integer (same precision, signed result), so substracting 1 from size give result of type Integer. Also (Size - 1) to Address gives signed result. Since Address is unsigned range checking kicks in: it considers negative result illegal.
Hmm. What I would expect from range checking is that the expression is computed with unlimited precision, and then the result is checked to fit in the destination type (conceptually, it doesn't have to be implemented this way). In other words, the type of the expression is not determined by types of operands, but by its environment.
In this example, Size - 1 should indeed be of type Integer, not because it is Cardinal - Integer, but because the second argument of Inc is declared as Integer (or at least, it is documented as such). Then adding (Size - 1) to Address should give a result of type SizeType (which is unsigned), because it is assigned back to Address.
I understand that this is essentially impossible to implement efficiently, since intermediary results in complex expressions would have to be computed with extra precision. However, this problem should not arise in the example above, because the only intermediary result here (Size - 1) is explicitely typed as Integer by the declaration of Inc.
Somewhat similar problems hit on AMD64, but this one is worse. We were discussing privatly with Frank rules for choosing result type of arithmetic operations. This particular case can be easily fixed by making type rules slightly smarter (it is not much effort to realize that 1 do not need sign), but it is large effort to make RTS work with range checking and without using excess precision.
-- Waldek Hebisch hebisch@math.uni.wroc.pl
On Mon, Feb 21, 2005 at 05:48:35PM +0100, Frank Heckenbach wrote: [...]
The attached patch should do this (and thus also avoid this problem without turning off range-checking).
It solves the problem in AddHeapRange, but seems to introduce another failure.
=== gpc tests ===
Running target any Running testsuite ...
UNSUPPORTED: aregextest.pas FAIL: bprealtest.pas
=== gpc Summary ===
# of tests 4537 # of expected passes 4535 # of unexpected failures 1 # of unsupported tests 1
TEST bprealtest.pas: ./a.out: error in exponentiation (Numerical result out of range) (error #700 at 804b08a)
Emil Jerabek