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; hash = null;
} }
private void parseHeader() { private void parseHeader() throws ProtocolException {
if (headerParsed) if (headerParsed)
return; 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 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 * 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 * With this in mind we ignore the inherited checkParse() and unCache() methods and implement a separate version
* of them for both header and transactions. * of them for both header and transactions.
@ -242,9 +242,15 @@ public class Block extends Message {
private void maybeParseHeader() { private void maybeParseHeader() {
if (headerParsed || bytes == null) if (headerParsed || bytes == null)
return; return;
parseHeader(); try {
if (!(headerBytesValid || transactionBytesValid)) parseHeader();
bytes = null; 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() { private void maybeParseTransactions() {

View File

@ -402,74 +402,104 @@ public abstract class Message implements Serializable {
return length; return length;
} }
long readUint32() { long readUint32() throws ProtocolException {
long u = Utils.readUint32(bytes, cursor); try {
cursor += 4; long u = Utils.readUint32(bytes, cursor);
return u; cursor += 4;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
} }
Sha256Hash readHash() { Sha256Hash readHash() throws ProtocolException {
byte[] hash = new byte[32]; try {
System.arraycopy(bytes, cursor, hash, 0, 32); byte[] hash = new byte[32];
// We have to flip it around, as it's been read off the wire in little endian. System.arraycopy(bytes, cursor, hash, 0, 32);
// Not the most efficient way to do this but the clearest. // We have to flip it around, as it's been read off the wire in little endian.
hash = Utils.reverseBytes(hash); // Not the most efficient way to do this but the clearest.
cursor += 32; hash = Utils.reverseBytes(hash);
return new Sha256Hash(hash); cursor += 32;
return new Sha256Hash(hash);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
} }
long readInt64() { long readInt64() throws ProtocolException {
long u = Utils.readInt64(bytes, cursor); try {
cursor += 8; long u = Utils.readInt64(bytes, cursor);
return u; cursor += 8;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
} }
BigInteger readUint64() { BigInteger readUint64() throws ProtocolException {
// Java does not have an unsigned 64 bit type. So scrape it off the wire then flip. try {
byte[] valbytes = new byte[8]; // Java does not have an unsigned 64 bit type. So scrape it off the wire then flip.
System.arraycopy(bytes, cursor, valbytes, 0, 8); byte[] valbytes = new byte[8];
valbytes = Utils.reverseBytes(valbytes); System.arraycopy(bytes, cursor, valbytes, 0, 8);
cursor += valbytes.length; valbytes = Utils.reverseBytes(valbytes);
return new BigInteger(valbytes); cursor += valbytes.length;
return new BigInteger(valbytes);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
} }
long readVarInt() { long readVarInt() throws ProtocolException {
return readVarInt(0); return readVarInt(0);
} }
long readVarInt(int offset) { long readVarInt(int offset) throws ProtocolException {
VarInt varint = new VarInt(bytes, cursor + offset); try {
cursor += offset + varint.getOriginalSizeInBytes(); VarInt varint = new VarInt(bytes, cursor + offset);
return varint.value; cursor += offset + varint.getOriginalSizeInBytes();
return varint.value;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
} }
byte[] readBytes(int length) { byte[] readBytes(int length) throws ProtocolException {
byte[] b = new byte[length]; try {
System.arraycopy(bytes, cursor, b, 0, length); byte[] b = new byte[length];
cursor += length; System.arraycopy(bytes, cursor, b, 0, length);
return b; cursor += length;
return b;
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
} }
byte[] readByteArray() { byte[] readByteArray() throws ProtocolException {
long len = readVarInt(); long len = readVarInt();
return readBytes((int)len); return readBytes((int)len);
} }
String readStr() { String readStr() throws ProtocolException {
VarInt varInt = new VarInt(bytes, cursor);
if (varInt.value == 0) {
cursor += 1;
return "";
}
cursor += varInt.getOriginalSizeInBytes();
byte[] characters = new byte[(int) varInt.value];
System.arraycopy(bytes, cursor, characters, 0, characters.length);
cursor += characters.length;
try { try {
return new String(characters, "UTF-8"); VarInt varInt = new VarInt(bytes, cursor);
} catch (UnsupportedEncodingException e) { if (varInt.value == 0) {
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported. cursor += 1;
return "";
}
cursor += varInt.getOriginalSizeInBytes();
byte[] characters = new byte[(int) varInt.value];
System.arraycopy(bytes, cursor, characters, 0, characters.length);
cursor += characters.length;
try {
return new String(characters, "UTF-8");
} 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);
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -121,7 +121,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
return scriptPubKey; 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 // 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 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) // 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); super(msg);
} }
public VerificationException(Exception e) {
super(e);
}
public VerificationException(String msg, Throwable t) { public VerificationException(String msg, Throwable t) {
super(msg, t); super(msg, t);
} }