The code computes the average of two integers using either division or signed right shift, and then uses the result as the index of an array. If the values being averaged are very large, this can overflow (resulting in the computation of a negative average).

This commit is contained in:
lei.lei 2018-06-20 14:14:28 +08:00
parent 39555fc266
commit facd3ee689
2 changed files with 19 additions and 4 deletions

View File

@ -82,7 +82,7 @@ public class DbSearcher
int l = 0, h = totalIndexBlocks;
long sip, eip, dataptr = 0;
while ( l <= h ) {
int m = (l + h) >> 1;
int m = Util.mean(l, h);
int p = (int)(firstIndexPtr + m * blen);
sip = Util.getIntLong(dbBinStr, p);
@ -194,7 +194,7 @@ public class DbSearcher
int l = 0, h = headerLength, sptr = 0, eptr = 0;
while ( l <= h ) {
int m = (l + h) >> 1;
int m = Util.mean(l, h);
//perfetc matched, just return it
if ( ip == HeaderSip[m] ) {
@ -247,7 +247,7 @@ public class DbSearcher
l = 0; h = blockLen / blen;
long sip, eip, dataptr = 0;
while ( l <= h ) {
int m = (l + h) >> 1;
int m = Util.mean(l, h);
int p = m * blen;
sip = Util.getIntLong(iBuffer, p);
if ( ip < sip ) {
@ -316,7 +316,7 @@ public class DbSearcher
byte[] buffer = new byte[blen];
long sip, eip, dataptr = 0;
while ( l <= h ) {
int m = (l + h) >> 1;
int m = Util.mean(l, h);
raf.seek(firstIndexPtr + m * blen); //set the file pointer
raf.readFully(buffer, 0, buffer.length);
sip = Util.getIntLong(buffer, 0);

View File

@ -140,4 +140,19 @@ public class Util
return true;
}
/**
* Returns the arithmetic mean of {@code x} and {@code y}, rounded towards
* negative infinity. This method is overflow resilient.
*
* code from guava 14.0
* com.google.common.math.IntMath.mean(int x, int y)
*
*/
public static int mean(int x, int y) {
// Efficient method for computing the arithmetic mean.
// The alternative (x + y) / 2 fails for large values.
// The alternative (x + y) >>> 1 fails for negative values.
return (x & y) + ((x ^ y) >> 1);
}
}