ERangeError
Brought to you by:
tpsfadmin
In XpHas.pas in routine XpCalcElfHash. Haven't been
able to identify the precise source, but with a large
(28MB) XML file, I reproducibly encounter the same
problem - an ERangeError is raised:
function XpCalcElfHash(const Buffer; BufSize : Integer)
: DWORD;
var
BufAsBytes : TXpByteArray absolute Buffer;
G : DWORD;
i : Integer;
begin
Result := 0;
for i := 0 to pred(BufSize) do begin
Result := (Result shl 4) + BufAsBytes[i];
G := Result and $F0000000;
if (G <> 0) then
Result := Result xor (G shr 24);
Result := Result and (not G);
end;
end;
Logged In: NO
Followup: I'm transforming my XML, using a stylesheet, into
another format. In my stylesheet I do something like:
<xsl:variable name="A_GLOBAL_VARIABLE"
select="//node_name[generate-id()=generate-id(key('knode_name',
.))]"/>
- 'node_name' nodes have many 'child' text nodes: in this
particular instance, something like 9000.
From what I've observed, it appears that in the course of
creating 'A_GLOBAL_VARIABLE', XpCalcElfHash is (ultimately)
called (by TXpStrHash.XhGetIndex - line 1197 in XpHas.pas).
TXpStrHash.XhGetIndex takes two parameters:
(const aKey: DOMString; const aCount : Longint)
The 'aKey' value passed to XpCalcElfHash is a concatonation
of all of the child text node values for a given 'node_name'
node. For the 'node_name' node that's triggering the
ERangeError, with its 9000 child text nodes, the total
length of 'aKey' is something like 66000+ characters.
Also in XpHas.pas, an array type called 'TXpByteArray' is
defined (line 51), like this:
TXpByteArray = array[0..65531] of byte;
If you look at again at the implementation of XpCalcElfHash,
you'll notice a local variable called BufAsBytes is declared:
BufAsBytes: TXpByteArray absolute Buffer;
...and inside of XpCalcElfHash, a counter is used to iterate
over BufAsBytes - from 0 to BufSize (the second parameter
passed into the function).
From the Delphi Helpfile:
'Absolute': You can create a new variable that resides at
the same address as another variable - so BufAsBytes 'maps'
to 'Buffer' (the first parameter passed into the function).
In this case - where the ERangeError is triggered, BufSize
is 66000+ characters, so eventually the counter exceeds the
maximum range defined by TXpByteArray, and that happens on
line 1349:
Result := (Result shl 4) + BufAsBytes[i];
So, above, the value of 'i' climbs beyond 65531.
I'm not really sure about how best to workaround the
problem. Top-of-my-head thoughts include
- redefine TXpByteArray with a larger range:
TXpByteArray = array[0..$FFFFFF] of byte;
- turn off range checking around the XpCalcElfHash function
by adding {$R+} at the start, and {$R-} at the end - pretend
the problem doesn't exist (but I've no idea what
implications that has elsewhere)