3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 23:32:16 +00:00

Catch out-of-bound reads and rethrow as ProtocolExceptions.

This commit is contained in:
Matt Corallo 2013-05-28 17:17:05 +02:00 committed by Mike Hearn
parent dbf7728b4f
commit a7987585b8
8 changed files with 97 additions and 57 deletions

View File

@ -148,7 +148,7 @@ public class Block extends Message {
hash = null;
}
private void parseHeader() {
private void parseHeader() throws ProtocolException {
if (headerParsed)
return;
@ -230,7 +230,7 @@ public class Block extends Message {
/*
* Block uses some special handling for lazy parsing and retention of cached bytes. Parsing and serializing the
* block header and the transaction list are both non-trivial so there are good efficiency gains to be had by
* separating them. There are many cases where a user may need access to access or change one or the other but not both.
* separating them. There are many cases where a user may need to access or change one or the other but not both.
*
* With this in mind we ignore the inherited checkParse() and unCache() methods and implement a separate version
* of them for both header and transactions.
@ -242,9 +242,15 @@ public class Block extends Message {
private void maybeParseHeader() {
if (headerParsed || bytes == null)
return;
try {
parseHeader();
if (!(headerBytesValid || transactionBytesValid))
bytes = null;
} catch (ProtocolException e) {
throw new LazyParseException(
"ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access",
e);
}
}
private void maybeParseTransactions() {

View File

@ -402,13 +402,18 @@ public abstract class Message implements Serializable {
return length;
}
long readUint32() {
long readUint32() throws ProtocolException {
try {
long u = Utils.readUint32(bytes, cursor);
cursor += 4;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
Sha256Hash readHash() {
Sha256Hash readHash() throws ProtocolException {
try {
byte[] hash = new byte[32];
System.arraycopy(bytes, cursor, hash, 0, 32);
// We have to flip it around, as it's been read off the wire in little endian.
@ -416,47 +421,67 @@ public abstract class Message implements Serializable {
hash = Utils.reverseBytes(hash);
cursor += 32;
return new Sha256Hash(hash);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
long readInt64() {
long readInt64() throws ProtocolException {
try {
long u = Utils.readInt64(bytes, cursor);
cursor += 8;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
BigInteger readUint64() {
BigInteger readUint64() throws ProtocolException {
try {
// Java does not have an unsigned 64 bit type. So scrape it off the wire then flip.
byte[] valbytes = new byte[8];
System.arraycopy(bytes, cursor, valbytes, 0, 8);
valbytes = Utils.reverseBytes(valbytes);
cursor += valbytes.length;
return new BigInteger(valbytes);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
long readVarInt() {
long readVarInt() throws ProtocolException {
return readVarInt(0);
}
long readVarInt(int offset) {
long readVarInt(int offset) throws ProtocolException {
try {
VarInt varint = new VarInt(bytes, cursor + offset);
cursor += offset + varint.getOriginalSizeInBytes();
return varint.value;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
byte[] readBytes(int length) {
byte[] readBytes(int length) throws ProtocolException {
try {
byte[] b = new byte[length];
System.arraycopy(bytes, cursor, b, 0, length);
cursor += length;
return b;
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
byte[] readByteArray() {
byte[] readByteArray() throws ProtocolException {
long len = readVarInt();
return readBytes((int)len);
}
String readStr() {
String readStr() throws ProtocolException {
try {
VarInt varInt = new VarInt(bytes, cursor);
if (varInt.value == 0) {
cursor += 1;
@ -471,6 +496,11 @@ public abstract class Message implements Serializable {
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
boolean hasMoreBytes() {

View File

@ -129,7 +129,7 @@ public class PeerAddress extends ChildMessage {
}
@Override
protected void parse() {
protected void parse() throws ProtocolException {
// Format of a serialized address:
// uint32 timestamp
// uint64 services (flags determining what the node can do)

View File

@ -54,7 +54,7 @@ public class Ping extends Message {
try {
nonce = readInt64();
hasNonce = true;
} catch(ArrayIndexOutOfBoundsException e) {
} catch(ProtocolException e) {
hasNonce = false;
}
length = hasNonce ? 8 : 0;

View File

@ -17,7 +17,7 @@
package com.google.bitcoin.core;
@SuppressWarnings("serial")
public class ProtocolException extends Exception {
public class ProtocolException extends VerificationException {
public ProtocolException(String msg) {
super(msg);

View File

@ -121,7 +121,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
this.parentTransaction = parentTransaction;
}
protected void parseLite() {
protected void parseLite() throws ProtocolException {
int curs = cursor;
int scriptLen = (int) readVarInt(36);
length = cursor - offset + scriptLen + 4;

View File

@ -121,7 +121,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
return scriptPubKey;
}
protected void parseLite() {
protected void parseLite() throws ProtocolException {
// TODO: There is no reason to use BigInteger for values, they are always smaller than 21 million * COIN
// The only reason to use BigInteger would be to properly read values from the reference implementation, however
// the reference implementation uses signed 64-bit integers for its values as well (though it probably shouldn't)

View File

@ -22,6 +22,10 @@ public class VerificationException extends Exception {
super(msg);
}
public VerificationException(Exception e) {
super(e);
}
public VerificationException(String msg, Throwable t) {
super(msg, t);
}