mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 12:34:32 +02:00
6792554: Java JAR Pack200 header checks are insufficent
Added several checks to ensure that the values read from the headers are consistent Reviewed-by: jrose
This commit is contained in:
parent
c357cbe4e0
commit
dcbd65a1c3
5 changed files with 97 additions and 379 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -94,6 +94,7 @@ void band::readData(int expectedLength) {
|
||||||
assert(!valc->isMalloc);
|
assert(!valc->isMalloc);
|
||||||
}
|
}
|
||||||
xvs.init(u->rp, u->rplimit, valc);
|
xvs.init(u->rp, u->rplimit, valc);
|
||||||
|
CHECK;
|
||||||
int X = xvs.getInt();
|
int X = xvs.getInt();
|
||||||
if (valc->S() != 0) {
|
if (valc->S() != 0) {
|
||||||
assert(valc->min <= -256);
|
assert(valc->min <= -256);
|
||||||
|
@ -117,6 +118,7 @@ void band::readData(int expectedLength) {
|
||||||
byte XB_byte = (byte) XB;
|
byte XB_byte = (byte) XB;
|
||||||
byte* XB_ptr = &XB_byte;
|
byte* XB_ptr = &XB_byte;
|
||||||
cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, null);
|
cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, null);
|
||||||
|
CHECK;
|
||||||
} else {
|
} else {
|
||||||
NOT_PRODUCT(byte* meta_rp0 = u->meta_rp);
|
NOT_PRODUCT(byte* meta_rp0 = u->meta_rp);
|
||||||
assert(u->meta_rp != null);
|
assert(u->meta_rp != null);
|
||||||
|
@ -215,8 +217,19 @@ int band::getIntTotal() {
|
||||||
if (length == 0) return 0;
|
if (length == 0) return 0;
|
||||||
if (total_memo > 0) return total_memo-1;
|
if (total_memo > 0) return total_memo-1;
|
||||||
int total = getInt();
|
int total = getInt();
|
||||||
|
// overflow checks require that none of the addends are <0,
|
||||||
|
// and that the partial sums never overflow (wrap negative)
|
||||||
|
if (total < 0) {
|
||||||
|
abort("overflow detected");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
for (int k = length-1; k > 0; k--) {
|
for (int k = length-1; k > 0; k--) {
|
||||||
|
int prev_total = total;
|
||||||
total += vs[0].getInt();
|
total += vs[0].getInt();
|
||||||
|
if (total < prev_total) {
|
||||||
|
abort("overflow detected");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rewind();
|
rewind();
|
||||||
total_memo = total+1;
|
total_memo = total+1;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -809,6 +809,7 @@ void coding_method::init(byte* &band_rp, byte* band_limit,
|
||||||
}
|
}
|
||||||
band_rp = vs.rp;
|
band_rp = vs.rp;
|
||||||
}
|
}
|
||||||
|
CHECK;
|
||||||
|
|
||||||
// Get an accurate upper limit now.
|
// Get an accurate upper limit now.
|
||||||
vs0.rplimit = band_rp;
|
vs0.rplimit = band_rp;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -155,6 +155,8 @@ enum { false, true };
|
||||||
#define CHECK_NULL_(y,p) _CHECK_DO((p)==null, return y)
|
#define CHECK_NULL_(y,p) _CHECK_DO((p)==null, return y)
|
||||||
#define CHECK_NULL_0(p) _CHECK_DO((p)==null, return 0)
|
#define CHECK_NULL_0(p) _CHECK_DO((p)==null, return 0)
|
||||||
|
|
||||||
|
#define CHECK_COUNT(t) if (t < 0){abort("bad value count");} CHECK
|
||||||
|
|
||||||
#define STR_TRUE "true"
|
#define STR_TRUE "true"
|
||||||
#define STR_FALSE "false"
|
#define STR_FALSE "false"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -504,15 +504,39 @@ void unpacker::read_file_header() {
|
||||||
enum {
|
enum {
|
||||||
MAGIC_BYTES = 4,
|
MAGIC_BYTES = 4,
|
||||||
AH_LENGTH_0 = 3, //minver, majver, options are outside of archive_size
|
AH_LENGTH_0 = 3, //minver, majver, options are outside of archive_size
|
||||||
|
AH_LENGTH_0_MAX = AH_LENGTH_0 + 1, // options might have 2 bytes
|
||||||
AH_LENGTH = 26, //maximum archive header length (w/ all fields)
|
AH_LENGTH = 26, //maximum archive header length (w/ all fields)
|
||||||
// Length contributions from optional header fields:
|
// Length contributions from optional header fields:
|
||||||
AH_FILE_HEADER_LEN = 5, // sizehi/lo/next/modtime/files
|
AH_FILE_HEADER_LEN = 5, // sizehi/lo/next/modtime/files
|
||||||
|
AH_ARCHIVE_SIZE_LEN = 2, // sizehi/lo only; part of AH_FILE_HEADER_LEN
|
||||||
AH_CP_NUMBER_LEN = 4, // int/float/long/double
|
AH_CP_NUMBER_LEN = 4, // int/float/long/double
|
||||||
AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers
|
AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers
|
||||||
AH_LENGTH_MIN = AH_LENGTH
|
AH_LENGTH_MIN = AH_LENGTH
|
||||||
-(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN),
|
-(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN),
|
||||||
|
ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - (AH_LENGTH_0 + AH_ARCHIVE_SIZE_LEN),
|
||||||
FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN
|
FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
assert(AH_LENGTH_MIN == 15); // # of UNSIGNED5 fields required after archive_magic
|
||||||
|
assert(ARCHIVE_SIZE_MIN == 10); // # of UNSIGNED5 fields required after archive_size
|
||||||
|
// An absolute minimum null archive is magic[4], {minver,majver,options}[3],
|
||||||
|
// archive_size[0], cp_counts[8], class_counts[4], for a total of 19 bytes.
|
||||||
|
// (Note that archive_size is optional; it may be 0..10 bytes in length.)
|
||||||
|
// The first read must capture everything up through the options field.
|
||||||
|
// This happens to work even if {minver,majver,options} is a pathological
|
||||||
|
// 15 bytes long. Legal pack files limit those three fields to 1+1+2 bytes.
|
||||||
|
assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0 * B_MAX);
|
||||||
|
|
||||||
|
// Up through archive_size, the largest possible archive header is
|
||||||
|
// magic[4], {minver,majver,options}[4], archive_size[10].
|
||||||
|
// (Note only the low 12 bits of options are allowed to be non-zero.)
|
||||||
|
// In order to parse archive_size, we need at least this many bytes
|
||||||
|
// in the first read. Of course, if archive_size_hi is more than
|
||||||
|
// a byte, we probably will fail to allocate the buffer, since it
|
||||||
|
// will be many gigabytes long. This is a practical, not an
|
||||||
|
// architectural limit to Pack200 archive sizes.
|
||||||
|
assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0_MAX + 2*B_MAX);
|
||||||
|
|
||||||
bool foreign_buf = (read_input_fn == null);
|
bool foreign_buf = (read_input_fn == null);
|
||||||
byte initbuf[FIRST_READ + C_SLOP + 200]; // 200 is for JAR I/O
|
byte initbuf[FIRST_READ + C_SLOP + 200]; // 200 is for JAR I/O
|
||||||
if (foreign_buf) {
|
if (foreign_buf) {
|
||||||
|
@ -528,7 +552,7 @@ void unpacker::read_file_header() {
|
||||||
// There is no way to tell the caller that we used only part of them.
|
// There is no way to tell the caller that we used only part of them.
|
||||||
// Therefore, the caller must use only a bare minimum of read-ahead.
|
// Therefore, the caller must use only a bare minimum of read-ahead.
|
||||||
if (inbytes.len > FIRST_READ) {
|
if (inbytes.len > FIRST_READ) {
|
||||||
abort("too much pushback");
|
abort("too much read-ahead");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
input.set(initbuf, sizeof(initbuf));
|
input.set(initbuf, sizeof(initbuf));
|
||||||
|
@ -538,7 +562,7 @@ void unpacker::read_file_header() {
|
||||||
rplimit += inbytes.len;
|
rplimit += inbytes.len;
|
||||||
bytes_read += inbytes.len;
|
bytes_read += inbytes.len;
|
||||||
}
|
}
|
||||||
// Read only 19 bytes, which is certain to contain #archive_size fields,
|
// Read only 19 bytes, which is certain to contain #archive_options fields,
|
||||||
// but is certain not to overflow past the archive_header.
|
// but is certain not to overflow past the archive_header.
|
||||||
input.b.len = FIRST_READ;
|
input.b.len = FIRST_READ;
|
||||||
if (!ensure_input(FIRST_READ))
|
if (!ensure_input(FIRST_READ))
|
||||||
|
@ -610,9 +634,9 @@ void unpacker::read_file_header() {
|
||||||
#undef ORBIT
|
#undef ORBIT
|
||||||
if ((archive_options & ~OPTION_LIMIT) != 0) {
|
if ((archive_options & ~OPTION_LIMIT) != 0) {
|
||||||
fprintf(errstrm, "Warning: Illegal archive options 0x%x\n",
|
fprintf(errstrm, "Warning: Illegal archive options 0x%x\n",
|
||||||
archive_options);
|
archive_options);
|
||||||
// Do not abort. If the format really changes, version numbers will bump.
|
abort("illegal archive options");
|
||||||
//abort("illegal archive options");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
|
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
|
||||||
|
@ -643,8 +667,17 @@ void unpacker::read_file_header() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (archive_size != 0) {
|
} else if (archive_size != 0) {
|
||||||
|
if (archive_size < ARCHIVE_SIZE_MIN) {
|
||||||
|
abort("impossible archive size"); // bad input data
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (archive_size < header_size_1) {
|
||||||
|
abort("too much read-ahead"); // somehow we pre-fetched too much?
|
||||||
|
return;
|
||||||
|
}
|
||||||
input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)),
|
input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)),
|
||||||
(size_t) header_size_0 + archive_size);
|
(size_t) header_size_0 + archive_size);
|
||||||
|
CHECK;
|
||||||
assert(input.limit()[0] == 0);
|
assert(input.limit()[0] == 0);
|
||||||
// Move all the bytes we read initially into the real buffer.
|
// Move all the bytes we read initially into the real buffer.
|
||||||
input.b.copyFrom(initbuf, header_size);
|
input.b.copyFrom(initbuf, header_size);
|
||||||
|
@ -659,6 +692,7 @@ void unpacker::read_file_header() {
|
||||||
rp = rplimit = input.base();
|
rp = rplimit = input.base();
|
||||||
// Set up input buffer as if we already read the header:
|
// Set up input buffer as if we already read the header:
|
||||||
input.b.copyFrom(initbuf, header_size);
|
input.b.copyFrom(initbuf, header_size);
|
||||||
|
CHECK;
|
||||||
rplimit += header_size;
|
rplimit += header_size;
|
||||||
while (ensure_input(input.limit() - rp)) {
|
while (ensure_input(input.limit() - rp)) {
|
||||||
size_t dataSoFar = input_remaining();
|
size_t dataSoFar = input_remaining();
|
||||||
|
@ -694,8 +728,10 @@ void unpacker::read_file_header() {
|
||||||
|
|
||||||
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
|
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
|
||||||
archive_next_count = hdr.getInt();
|
archive_next_count = hdr.getInt();
|
||||||
|
CHECK_COUNT(archive_next_count);
|
||||||
archive_modtime = hdr.getInt();
|
archive_modtime = hdr.getInt();
|
||||||
file_count = hdr.getInt();
|
file_count = hdr.getInt();
|
||||||
|
CHECK_COUNT(file_count);
|
||||||
hdrVals += 3;
|
hdrVals += 3;
|
||||||
} else {
|
} else {
|
||||||
hdrValsSkipped += 3;
|
hdrValsSkipped += 3;
|
||||||
|
@ -703,7 +739,9 @@ void unpacker::read_file_header() {
|
||||||
|
|
||||||
if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) {
|
if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) {
|
||||||
band_headers_size = hdr.getInt();
|
band_headers_size = hdr.getInt();
|
||||||
|
CHECK_COUNT(band_headers_size);
|
||||||
attr_definition_count = hdr.getInt();
|
attr_definition_count = hdr.getInt();
|
||||||
|
CHECK_COUNT(attr_definition_count);
|
||||||
hdrVals += 2;
|
hdrVals += 2;
|
||||||
} else {
|
} else {
|
||||||
hdrValsSkipped += 2;
|
hdrValsSkipped += 2;
|
||||||
|
@ -723,13 +761,16 @@ void unpacker::read_file_header() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cp_counts[k] = hdr.getInt();
|
cp_counts[k] = hdr.getInt();
|
||||||
|
CHECK_COUNT(cp_counts[k]);
|
||||||
hdrVals += 1;
|
hdrVals += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ic_count = hdr.getInt();
|
ic_count = hdr.getInt();
|
||||||
|
CHECK_COUNT(ic_count);
|
||||||
default_class_minver = hdr.getInt();
|
default_class_minver = hdr.getInt();
|
||||||
default_class_majver = hdr.getInt();
|
default_class_majver = hdr.getInt();
|
||||||
class_count = hdr.getInt();
|
class_count = hdr.getInt();
|
||||||
|
CHECK_COUNT(class_count);
|
||||||
hdrVals += 4;
|
hdrVals += 4;
|
||||||
|
|
||||||
// done with archive_header
|
// done with archive_header
|
||||||
|
@ -783,7 +824,6 @@ void unpacker::read_file_header() {
|
||||||
bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error);
|
bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void unpacker::finish() {
|
void unpacker::finish() {
|
||||||
if (verbose >= 1) {
|
if (verbose >= 1) {
|
||||||
fprintf(errstrm,
|
fprintf(errstrm,
|
||||||
|
@ -2089,6 +2129,7 @@ void unpacker::read_classes() {
|
||||||
|
|
||||||
field_descr.readData(field_count);
|
field_descr.readData(field_count);
|
||||||
read_attrs(ATTR_CONTEXT_FIELD, field_count);
|
read_attrs(ATTR_CONTEXT_FIELD, field_count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
method_descr.readData(method_count);
|
method_descr.readData(method_count);
|
||||||
read_attrs(ATTR_CONTEXT_METHOD, method_count);
|
read_attrs(ATTR_CONTEXT_METHOD, method_count);
|
||||||
|
@ -2096,6 +2137,7 @@ void unpacker::read_classes() {
|
||||||
CHECK;
|
CHECK;
|
||||||
|
|
||||||
read_attrs(ATTR_CONTEXT_CLASS, class_count);
|
read_attrs(ATTR_CONTEXT_CLASS, class_count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
read_code_headers();
|
read_code_headers();
|
||||||
|
|
||||||
|
@ -2122,10 +2164,12 @@ void unpacker::read_attrs(int attrc, int obj_count) {
|
||||||
assert(endsWith(xxx_flags_hi.name, "_flags_hi"));
|
assert(endsWith(xxx_flags_hi.name, "_flags_hi"));
|
||||||
if (haveLongFlags)
|
if (haveLongFlags)
|
||||||
xxx_flags_hi.readData(obj_count);
|
xxx_flags_hi.readData(obj_count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
band& xxx_flags_lo = ad.xxx_flags_lo();
|
band& xxx_flags_lo = ad.xxx_flags_lo();
|
||||||
assert(endsWith(xxx_flags_lo.name, "_flags_lo"));
|
assert(endsWith(xxx_flags_lo.name, "_flags_lo"));
|
||||||
xxx_flags_lo.readData(obj_count);
|
xxx_flags_lo.readData(obj_count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
// pre-scan flags, counting occurrences of each index bit
|
// pre-scan flags, counting occurrences of each index bit
|
||||||
julong indexMask = ad.flagIndexMask(); // which flag bits are index bits?
|
julong indexMask = ad.flagIndexMask(); // which flag bits are index bits?
|
||||||
|
@ -2148,11 +2192,13 @@ void unpacker::read_attrs(int attrc, int obj_count) {
|
||||||
assert(endsWith(xxx_attr_count.name, "_attr_count"));
|
assert(endsWith(xxx_attr_count.name, "_attr_count"));
|
||||||
// There is one count element for each 1<<16 bit set in flags:
|
// There is one count element for each 1<<16 bit set in flags:
|
||||||
xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW));
|
xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW));
|
||||||
|
CHECK;
|
||||||
|
|
||||||
band& xxx_attr_indexes = ad.xxx_attr_indexes();
|
band& xxx_attr_indexes = ad.xxx_attr_indexes();
|
||||||
assert(endsWith(xxx_attr_indexes.name, "_attr_indexes"));
|
assert(endsWith(xxx_attr_indexes.name, "_attr_indexes"));
|
||||||
int overflowIndexCount = xxx_attr_count.getIntTotal();
|
int overflowIndexCount = xxx_attr_count.getIntTotal();
|
||||||
xxx_attr_indexes.readData(overflowIndexCount);
|
xxx_attr_indexes.readData(overflowIndexCount);
|
||||||
|
CHECK;
|
||||||
// pre-scan attr indexes, counting occurrences of each value
|
// pre-scan attr indexes, counting occurrences of each value
|
||||||
for (i = 0; i < overflowIndexCount; i++) {
|
for (i = 0; i < overflowIndexCount; i++) {
|
||||||
idx = xxx_attr_indexes.getInt();
|
idx = xxx_attr_indexes.getInt();
|
||||||
|
@ -2183,6 +2229,7 @@ void unpacker::read_attrs(int attrc, int obj_count) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ad.xxx_attr_calls().readData(backwardCounts);
|
ad.xxx_attr_calls().readData(backwardCounts);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
// Read built-in bands.
|
// Read built-in bands.
|
||||||
// Mostly, these are hand-coded equivalents to readBandData().
|
// Mostly, these are hand-coded equivalents to readBandData().
|
||||||
|
@ -2191,42 +2238,53 @@ void unpacker::read_attrs(int attrc, int obj_count) {
|
||||||
|
|
||||||
count = ad.predefCount(CLASS_ATTR_SourceFile);
|
count = ad.predefCount(CLASS_ATTR_SourceFile);
|
||||||
class_SourceFile_RUN.readData(count);
|
class_SourceFile_RUN.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
count = ad.predefCount(CLASS_ATTR_EnclosingMethod);
|
count = ad.predefCount(CLASS_ATTR_EnclosingMethod);
|
||||||
class_EnclosingMethod_RC.readData(count);
|
class_EnclosingMethod_RC.readData(count);
|
||||||
class_EnclosingMethod_RDN.readData(count);
|
class_EnclosingMethod_RDN.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
count = ad.predefCount(X_ATTR_Signature);
|
count = ad.predefCount(X_ATTR_Signature);
|
||||||
class_Signature_RS.readData(count);
|
class_Signature_RS.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
|
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
|
||||||
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
|
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
|
||||||
|
|
||||||
count = ad.predefCount(CLASS_ATTR_InnerClasses);
|
count = ad.predefCount(CLASS_ATTR_InnerClasses);
|
||||||
class_InnerClasses_N.readData(count);
|
class_InnerClasses_N.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
count = class_InnerClasses_N.getIntTotal();
|
count = class_InnerClasses_N.getIntTotal();
|
||||||
class_InnerClasses_RC.readData(count);
|
class_InnerClasses_RC.readData(count);
|
||||||
class_InnerClasses_F.readData(count);
|
class_InnerClasses_F.readData(count);
|
||||||
|
CHECK;
|
||||||
// Drop remaining columns wherever flags are zero:
|
// Drop remaining columns wherever flags are zero:
|
||||||
count -= class_InnerClasses_F.getIntCount(0);
|
count -= class_InnerClasses_F.getIntCount(0);
|
||||||
class_InnerClasses_outer_RCN.readData(count);
|
class_InnerClasses_outer_RCN.readData(count);
|
||||||
class_InnerClasses_name_RUN.readData(count);
|
class_InnerClasses_name_RUN.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
count = ad.predefCount(CLASS_ATTR_ClassFile_version);
|
count = ad.predefCount(CLASS_ATTR_ClassFile_version);
|
||||||
class_ClassFile_version_minor_H.readData(count);
|
class_ClassFile_version_minor_H.readData(count);
|
||||||
class_ClassFile_version_major_H.readData(count);
|
class_ClassFile_version_major_H.readData(count);
|
||||||
|
CHECK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ATTR_CONTEXT_FIELD:
|
case ATTR_CONTEXT_FIELD:
|
||||||
|
|
||||||
count = ad.predefCount(FIELD_ATTR_ConstantValue);
|
count = ad.predefCount(FIELD_ATTR_ConstantValue);
|
||||||
field_ConstantValue_KQ.readData(count);
|
field_ConstantValue_KQ.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
count = ad.predefCount(X_ATTR_Signature);
|
count = ad.predefCount(X_ATTR_Signature);
|
||||||
field_Signature_RS.readData(count);
|
field_Signature_RS.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
|
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
|
||||||
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
|
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
|
||||||
|
CHECK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ATTR_CONTEXT_METHOD:
|
case ATTR_CONTEXT_METHOD:
|
||||||
|
@ -2238,15 +2296,18 @@ void unpacker::read_attrs(int attrc, int obj_count) {
|
||||||
method_Exceptions_N.readData(count);
|
method_Exceptions_N.readData(count);
|
||||||
count = method_Exceptions_N.getIntTotal();
|
count = method_Exceptions_N.getIntTotal();
|
||||||
method_Exceptions_RC.readData(count);
|
method_Exceptions_RC.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
count = ad.predefCount(X_ATTR_Signature);
|
count = ad.predefCount(X_ATTR_Signature);
|
||||||
method_Signature_RS.readData(count);
|
method_Signature_RS.readData(count);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
|
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
|
||||||
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
|
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
|
||||||
ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations);
|
ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations);
|
||||||
ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations);
|
ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations);
|
||||||
ad.readBandData(METHOD_ATTR_AnnotationDefault);
|
ad.readBandData(METHOD_ATTR_AnnotationDefault);
|
||||||
|
CHECK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ATTR_CONTEXT_CODE:
|
case ATTR_CONTEXT_CODE:
|
||||||
|
@ -2258,8 +2319,10 @@ void unpacker::read_attrs(int attrc, int obj_count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
code_StackMapTable_N.readData(count);
|
code_StackMapTable_N.readData(count);
|
||||||
|
CHECK;
|
||||||
count = code_StackMapTable_N.getIntTotal();
|
count = code_StackMapTable_N.getIntTotal();
|
||||||
code_StackMapTable_frame_T.readData(count);
|
code_StackMapTable_frame_T.readData(count);
|
||||||
|
CHECK;
|
||||||
// the rest of it depends in a complicated way on frame tags
|
// the rest of it depends in a complicated way on frame tags
|
||||||
{
|
{
|
||||||
int fat_frame_count = 0;
|
int fat_frame_count = 0;
|
||||||
|
@ -2293,18 +2356,23 @@ void unpacker::read_attrs(int attrc, int obj_count) {
|
||||||
// deal completely with fat frames:
|
// deal completely with fat frames:
|
||||||
offset_count += fat_frame_count;
|
offset_count += fat_frame_count;
|
||||||
code_StackMapTable_local_N.readData(fat_frame_count);
|
code_StackMapTable_local_N.readData(fat_frame_count);
|
||||||
|
CHECK;
|
||||||
type_count += code_StackMapTable_local_N.getIntTotal();
|
type_count += code_StackMapTable_local_N.getIntTotal();
|
||||||
code_StackMapTable_stack_N.readData(fat_frame_count);
|
code_StackMapTable_stack_N.readData(fat_frame_count);
|
||||||
type_count += code_StackMapTable_stack_N.getIntTotal();
|
type_count += code_StackMapTable_stack_N.getIntTotal();
|
||||||
|
CHECK;
|
||||||
// read the rest:
|
// read the rest:
|
||||||
code_StackMapTable_offset.readData(offset_count);
|
code_StackMapTable_offset.readData(offset_count);
|
||||||
code_StackMapTable_T.readData(type_count);
|
code_StackMapTable_T.readData(type_count);
|
||||||
|
CHECK;
|
||||||
// (7) [RCH]
|
// (7) [RCH]
|
||||||
count = code_StackMapTable_T.getIntCount(7);
|
count = code_StackMapTable_T.getIntCount(7);
|
||||||
code_StackMapTable_RC.readData(count);
|
code_StackMapTable_RC.readData(count);
|
||||||
|
CHECK;
|
||||||
// (8) [PH]
|
// (8) [PH]
|
||||||
count = code_StackMapTable_T.getIntCount(8);
|
count = code_StackMapTable_T.getIntCount(8);
|
||||||
code_StackMapTable_P.readData(count);
|
code_StackMapTable_P.readData(count);
|
||||||
|
CHECK;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = ad.predefCount(CODE_ATTR_LineNumberTable);
|
count = ad.predefCount(CODE_ATTR_LineNumberTable);
|
||||||
|
@ -2626,6 +2694,7 @@ void unpacker::read_code_headers() {
|
||||||
code_max_na_locals.readData();
|
code_max_na_locals.readData();
|
||||||
code_handler_count.readData();
|
code_handler_count.readData();
|
||||||
totalHandlerCount += code_handler_count.getIntTotal();
|
totalHandlerCount += code_handler_count.getIntTotal();
|
||||||
|
CHECK;
|
||||||
|
|
||||||
// Read handler specifications.
|
// Read handler specifications.
|
||||||
// Cf. PackageReader.readCodeHandlers.
|
// Cf. PackageReader.readCodeHandlers.
|
||||||
|
@ -2633,8 +2702,10 @@ void unpacker::read_code_headers() {
|
||||||
code_handler_end_PO.readData(totalHandlerCount);
|
code_handler_end_PO.readData(totalHandlerCount);
|
||||||
code_handler_catch_PO.readData(totalHandlerCount);
|
code_handler_catch_PO.readData(totalHandlerCount);
|
||||||
code_handler_class_RCN.readData(totalHandlerCount);
|
code_handler_class_RCN.readData(totalHandlerCount);
|
||||||
|
CHECK;
|
||||||
|
|
||||||
read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount);
|
read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount);
|
||||||
|
CHECK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool is_in_range(uint n, uint min, uint max) {
|
static inline bool is_in_range(uint n, uint min, uint max) {
|
||||||
|
|
|
@ -1,369 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
||||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
||||||
* have any questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @test
|
|
||||||
* @bug 6755943
|
|
||||||
* @summary Checks any memory overruns in archive length.
|
|
||||||
* @run main/timeout=1200 MemoryAllocatorTest
|
|
||||||
*/
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.MappedByteBuffer;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class MemoryAllocatorTest {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The smallest possible pack file with 1 empty resource
|
|
||||||
*/
|
|
||||||
static int[] magic = {
|
|
||||||
0xCA, 0xFE, 0xD0, 0x0D
|
|
||||||
};
|
|
||||||
static int[] version_info = {
|
|
||||||
0x07, // minor
|
|
||||||
0x96 // major
|
|
||||||
};
|
|
||||||
static int[] option = {
|
|
||||||
0x10
|
|
||||||
};
|
|
||||||
static int[] size_hi = {
|
|
||||||
0x00
|
|
||||||
};
|
|
||||||
static int[] size_lo_ulong = {
|
|
||||||
0xFF, 0xFC, 0xFC, 0xFC, 0xFC // ULONG_MAX 0xFFFFFFFF
|
|
||||||
};
|
|
||||||
static int[] size_lo_correct = {
|
|
||||||
0x17
|
|
||||||
};
|
|
||||||
static int[] data = {
|
|
||||||
0x00, 0xEC, 0xDA, 0xDE, 0xF8, 0x45, 0x01, 0x02,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x31, 0x01, 0x00
|
|
||||||
};
|
|
||||||
// End of pack file data
|
|
||||||
|
|
||||||
static final String JAVA_HOME = System.getProperty("java.home");
|
|
||||||
|
|
||||||
static final boolean debug = Boolean.getBoolean("MemoryAllocatorTest.Debug");
|
|
||||||
static final boolean WINDOWS = System.getProperty("os.name").startsWith("Windows");
|
|
||||||
static final boolean LINUX = System.getProperty("os.name").startsWith("Linux");
|
|
||||||
static final boolean SIXTYFOUR_BIT = System.getProperty("sun.arch.data.model", "32").equals("64");
|
|
||||||
static final private int EXPECTED_EXIT_CODE = (WINDOWS) ? -1 : 255;
|
|
||||||
|
|
||||||
static int testExitValue = 0;
|
|
||||||
|
|
||||||
static byte[] bytes(int[] a) {
|
|
||||||
byte[] b = new byte[a.length];
|
|
||||||
for (int i = 0; i < b.length; i++) {
|
|
||||||
b[i] = (byte) a[i];
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void createPackFile(boolean good, File packFile) throws IOException {
|
|
||||||
FileOutputStream fos = new FileOutputStream(packFile);
|
|
||||||
fos.write(bytes(magic));
|
|
||||||
fos.write(bytes(version_info));
|
|
||||||
fos.write(bytes(option));
|
|
||||||
fos.write(bytes(size_hi));
|
|
||||||
if (good) {
|
|
||||||
fos.write(bytes(size_lo_correct));
|
|
||||||
} else {
|
|
||||||
fos.write(bytes(size_lo_ulong));
|
|
||||||
}
|
|
||||||
fos.write(bytes(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This method modifies the LSB of the size_lo for various wicked
|
|
||||||
* values between MAXINT-0x3F and MAXINT.
|
|
||||||
*/
|
|
||||||
static int modifyPackFile(File packFile) throws IOException {
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(packFile, "rws");
|
|
||||||
long len = packFile.length();
|
|
||||||
FileChannel fc = raf.getChannel();
|
|
||||||
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_WRITE, 0, len);
|
|
||||||
int pos = magic.length + version_info.length + option.length +
|
|
||||||
size_hi.length;
|
|
||||||
byte value = bb.get(pos);
|
|
||||||
value--;
|
|
||||||
bb.position(pos);
|
|
||||||
bb.put(value);
|
|
||||||
bb.force();
|
|
||||||
fc.truncate(len);
|
|
||||||
fc.close();
|
|
||||||
return value & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getUnpack200Cmd() throws Exception {
|
|
||||||
File binDir = new File(JAVA_HOME, "bin");
|
|
||||||
File unpack200File = WINDOWS
|
|
||||||
? new File(binDir, "unpack200.exe")
|
|
||||||
: new File(binDir, "unpack200");
|
|
||||||
|
|
||||||
String cmd = unpack200File.getAbsolutePath();
|
|
||||||
if (!unpack200File.canExecute()) {
|
|
||||||
throw new Exception("please check" +
|
|
||||||
cmd + " exists and is executable");
|
|
||||||
}
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TestResult runUnpacker(File packFile) throws Exception {
|
|
||||||
if (!packFile.exists()) {
|
|
||||||
throw new Exception("please check" + packFile + " exists");
|
|
||||||
}
|
|
||||||
ArrayList<String> alist = new ArrayList<String>();
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(getUnpack200Cmd(),
|
|
||||||
packFile.getName(), "testout.jar");
|
|
||||||
Map<String, String> env = pb.environment();
|
|
||||||
pb.directory(new File("."));
|
|
||||||
int retval = 0;
|
|
||||||
try {
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process p = pb.start();
|
|
||||||
BufferedReader rd = new BufferedReader(
|
|
||||||
new InputStreamReader(p.getInputStream()), 8192);
|
|
||||||
String in = rd.readLine();
|
|
||||||
while (in != null) {
|
|
||||||
alist.add(in);
|
|
||||||
System.out.println(in);
|
|
||||||
in = rd.readLine();
|
|
||||||
}
|
|
||||||
retval = p.waitFor();
|
|
||||||
p.destroy();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
throw new RuntimeException(ex.getMessage());
|
|
||||||
}
|
|
||||||
return new TestResult("", retval, alist);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The debug version builds of unpack200 call abort(3) which might set
|
|
||||||
* an unexpected return value, therefore this test is to determine
|
|
||||||
* if we are using a product or non-product build and check the
|
|
||||||
* return value appropriately.
|
|
||||||
*/
|
|
||||||
static boolean isNonProductVersion() throws Exception {
|
|
||||||
ArrayList<String> alist = new ArrayList<String>();
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(getUnpack200Cmd(), "--version");
|
|
||||||
Map<String, String> env = pb.environment();
|
|
||||||
pb.directory(new File("."));
|
|
||||||
int retval = 0;
|
|
||||||
try {
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process p = pb.start();
|
|
||||||
BufferedReader rd = new BufferedReader(
|
|
||||||
new InputStreamReader(p.getInputStream()), 8192);
|
|
||||||
String in = rd.readLine();
|
|
||||||
while (in != null) {
|
|
||||||
alist.add(in);
|
|
||||||
System.out.println(in);
|
|
||||||
in = rd.readLine();
|
|
||||||
}
|
|
||||||
retval = p.waitFor();
|
|
||||||
p.destroy();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
throw new RuntimeException(ex.getMessage());
|
|
||||||
}
|
|
||||||
for (String x : alist) {
|
|
||||||
if (x.contains("non-product")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param args the command line arguments
|
|
||||||
* @throws java.lang.Exception
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
|
|
||||||
File packFile = new File("tiny.pack");
|
|
||||||
boolean isNPVersion = isNonProductVersion();
|
|
||||||
|
|
||||||
// Create a good pack file and test if everything is ok
|
|
||||||
createPackFile(true, packFile);
|
|
||||||
TestResult tr = runUnpacker(packFile);
|
|
||||||
tr.setDescription("a good pack file");
|
|
||||||
tr.checkPositive();
|
|
||||||
tr.isOK();
|
|
||||||
System.out.println(tr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* jprt systems on windows and linux seem to have abundant memory
|
|
||||||
* therefore can take a very long time to run, and even if it does
|
|
||||||
* the error message is not accurate for us to discern if the test
|
|
||||||
* passess successfully.
|
|
||||||
*/
|
|
||||||
if (SIXTYFOUR_BIT && (LINUX || WINDOWS)) {
|
|
||||||
System.out.println("Warning: Windows/Linux 64bit tests passes vacuously");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* debug builds call abort, the exit code under these conditions
|
|
||||||
* are not really relevant.
|
|
||||||
*/
|
|
||||||
if (isNPVersion) {
|
|
||||||
System.out.println("Warning: non-product build: exit values not checked");
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a bad pack file
|
|
||||||
createPackFile(false, packFile);
|
|
||||||
tr = runUnpacker(packFile);
|
|
||||||
tr.setDescription("a wicked pack file");
|
|
||||||
tr.contains("Native allocation failed");
|
|
||||||
if(!isNPVersion) {
|
|
||||||
tr.checkValue(EXPECTED_EXIT_CODE);
|
|
||||||
}
|
|
||||||
System.out.println(tr);
|
|
||||||
int value = modifyPackFile(packFile);
|
|
||||||
tr.setDescription("value=" + value);
|
|
||||||
|
|
||||||
// continue creating bad pack files by modifying the specimen pack file.
|
|
||||||
while (value >= 0xc0) {
|
|
||||||
tr = runUnpacker(packFile);
|
|
||||||
tr.contains("Native allocation failed");
|
|
||||||
if (!isNPVersion) {
|
|
||||||
tr.checkValue(EXPECTED_EXIT_CODE);
|
|
||||||
}
|
|
||||||
tr.setDescription("wicked value=0x" +
|
|
||||||
Integer.toHexString(value & 0xFF));
|
|
||||||
System.out.println(tr);
|
|
||||||
value = modifyPackFile(packFile);
|
|
||||||
}
|
|
||||||
if (testExitValue != 0) {
|
|
||||||
throw new Exception("Pack200 archive length tests(" +
|
|
||||||
testExitValue + ") failed ");
|
|
||||||
} else {
|
|
||||||
System.out.println("All tests pass");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A class to encapsulate the test results and stuff, with some ease
|
|
||||||
* of use methods to check the test results.
|
|
||||||
*/
|
|
||||||
static class TestResult {
|
|
||||||
|
|
||||||
StringBuilder status;
|
|
||||||
int exitValue;
|
|
||||||
List<String> testOutput;
|
|
||||||
String description;
|
|
||||||
|
|
||||||
public TestResult(String str, int rv, List<String> oList) {
|
|
||||||
status = new StringBuilder(str);
|
|
||||||
exitValue = rv;
|
|
||||||
testOutput = oList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkValue(int value) {
|
|
||||||
if (exitValue != value) {
|
|
||||||
status =
|
|
||||||
status.append(" Error: test expected exit value " +
|
|
||||||
value + "got " + exitValue);
|
|
||||||
testExitValue++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkNegative() {
|
|
||||||
if (exitValue == 0) {
|
|
||||||
status = status.append(
|
|
||||||
" Error: test did not expect 0 exit value");
|
|
||||||
|
|
||||||
testExitValue++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkPositive() {
|
|
||||||
if (exitValue != 0) {
|
|
||||||
status = status.append(
|
|
||||||
" Error: test did not return 0 exit value");
|
|
||||||
testExitValue++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isOK() {
|
|
||||||
return exitValue == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isZeroOutput() {
|
|
||||||
if (!testOutput.isEmpty()) {
|
|
||||||
status = status.append(" Error: No message from cmd please");
|
|
||||||
testExitValue++;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isNotZeroOutput() {
|
|
||||||
if (testOutput.isEmpty()) {
|
|
||||||
status = status.append(" Error: Missing message");
|
|
||||||
testExitValue++;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
if (debug) {
|
|
||||||
for (String x : testOutput) {
|
|
||||||
status = status.append(x + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (description != null) {
|
|
||||||
status.insert(0, description);
|
|
||||||
}
|
|
||||||
return status.append("\nexitValue = " + exitValue).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean contains(String str) {
|
|
||||||
for (String x : testOutput) {
|
|
||||||
if (x.contains(str)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
status = status.append(" Error: string <" + str + "> not found ");
|
|
||||||
testExitValue++;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue