binpac: Improve parsing of known-length, static-size arrays

In this case, the bounds checking for individual elements can be
optimized out of the parsing-loop in favor of a single, array-wide
bounds check beforehand.
This commit is contained in:
Jon Siwek 2018-05-18 10:31:54 -05:00 committed by Tim Wojtulewicz
parent d6fc439c21
commit 0a05aa92fc

View file

@ -280,6 +280,12 @@ void ArrayType::GenArrayLength(Output *out_cc, Env *env, const DataPtr& data)
// Check for overlong array length. We cap it at the
// maximum data size as we won't store more elements.
// e.g. this helps prevent user-controlled length fields
// from causing an excessive memory-allocation (for
// the array we'll be parsing into) unless they actually
// sent enough data to go along with it. Note that this check
// is *not* looking for whether the contents of the array will
// extend past the end of the data buffer.
out_cc->println("if ( t_begin_of_data + %s > t_end_of_data + 1 || t_begin_of_data + %s < t_begin_of_data )",
env->LValue(arraylength_var()), env->LValue(arraylength_var()));
out_cc->inc_indent();
@ -298,6 +304,28 @@ void ArrayType::GenArrayLength(Output *out_cc, Env *env, const DataPtr& data)
env->LValue(arraylength_var()));
out_cc->println("}");
out_cc->dec_indent();
if ( elemtype_->StaticSize(env) != -1 )
{
// Boundary check the entire array if elements have static size.
string array_size = strfmt("((%d) * (%s))",
elemtype_->StaticSize(env),
env->RValue(arraylength_var()));
out_cc->println("// Check bounds for static-size array: %s",
data_id_str_.c_str());
out_cc->println("if ( t_begin_of_data + %s > t_end_of_data || "
"t_begin_of_data + %s < t_begin_of_data )",
array_size.c_str(), array_size.c_str());
out_cc->inc_indent();
out_cc->println("throw binpac::ExceptionOutOfBound(\"%s\",",
data_id_str_.c_str());
out_cc->println(" %s, (%s) - (%s));",
array_size.c_str(),
env->RValue(end_of_data),
env->RValue(begin_of_data));
out_cc->dec_indent();
elemtype_->SetBoundaryChecked();
}
}
else if ( attr_restofdata_ )
{