Implement will_overflow ().

This commit is contained in:
Garret Rieger 2020-11-02 14:51:39 -08:00
parent 6b1ea4cbe7
commit 8ebe5d734f
2 changed files with 114 additions and 4 deletions

View File

@ -50,6 +50,8 @@ struct graph_t
bool removed_nil = false;
for (unsigned i = 0; i < objects.length; i++)
{
// TODO(grieger): check all links point to valid objects.
// If this graph came from a serialization buffer object 0 is the
// nil object. We don't need it for our purposes here so drop it.
if (i == 0 && !objects[i])
@ -151,16 +153,79 @@ struct graph_t
/*
* Will any offsets overflow on graph when it's serialized?
*/
bool will_overflow()
bool will_overflow ()
{
// TODO(garretrieger): implement me.
// - Check for offsets that exceed their width or;
// - are negative if using a non-signed link.
hb_map_t start_positions;
hb_map_t end_positions;
unsigned current_pos = 0;
for (int i = objects_.length - 1; i >= 0; i--)
{
start_positions.set (i, current_pos);
current_pos += objects_[i].tail - objects_[i].head;
end_positions.set (i, current_pos);
}
for (unsigned parent_idx = 0; parent_idx < objects_.length; parent_idx++)
{
for (const auto& link : objects_[parent_idx].links)
{
int64_t offset = compute_offset (parent_idx,
link,
start_positions,
end_positions);
if (!is_valid_offset (offset, link)) return true;
}
}
return false;
}
private:
int64_t compute_offset (
unsigned parent_idx,
const hb_serialize_context_t::object_t::link_t& link,
const hb_map_t& start_positions,
const hb_map_t& end_positions)
{
unsigned child_idx = link.objidx;
int64_t offset = 0;
switch ((hb_serialize_context_t::whence_t) link.whence) {
case hb_serialize_context_t::whence_t::Head:
offset = start_positions[child_idx] - start_positions[parent_idx]; break;
case hb_serialize_context_t::whence_t::Tail:
offset = start_positions[child_idx] - end_positions[parent_idx]; break;
case hb_serialize_context_t::whence_t::Absolute:
offset = start_positions[child_idx]; break;
}
assert (offset >= link.bias);
offset -= link.bias;
return offset;
}
bool is_valid_offset (int64_t offset,
const hb_serialize_context_t::object_t::link_t& link)
{
if (link.is_signed)
{
if (link.is_wide)
return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31);
else
return offset >= -(1 << 15) && offset < (1 << 15);
}
else
{
if (link.is_wide)
return offset >= 0 && offset < ((int64_t) 1 << 32);
else
return offset >= 0 && offset < (1 << 16);
}
}
/*
* Updates all objidx's in all links using the provided mapping.
*/

View File

@ -24,6 +24,8 @@
* Google Author(s): Garret Rieger
*/
#include <string>
#include "hb-repacker.hh"
#include "hb-open-type.hh"
@ -70,6 +72,25 @@ populate_serializer_simple (hb_serialize_context_t* c)
c->end_serialize();
}
static void
populate_serializer_with_overflow (hb_serialize_context_t* c)
{
std::string large_string(40000, 'a');
c->start_serialize<char> ();
unsigned obj_1 = add_object (large_string.c_str(), 40000, c);
unsigned obj_2 = add_object (large_string.c_str(), 40000, c);
unsigned obj_3 = add_object (large_string.c_str(), 40000, c);
start_object ("abc", 3, c);
add_offset (obj_3, c);
add_offset (obj_2, c);
add_offset (obj_1, c);
c->pop_pack ();
c->end_serialize();
}
static void
populate_serializer_complex_1 (hb_serialize_context_t* c)
{
@ -196,10 +217,34 @@ test_serialize ()
free (buffer_2);
}
static void test_will_overflow_1 ()
{
size_t buffer_size = 100;
void* buffer = malloc (buffer_size);
hb_serialize_context_t c (buffer, buffer_size);
populate_serializer_complex_2 (&c);
graph_t graph (c.object_graph ());
assert (!graph.will_overflow ());
}
static void test_will_overflow_2 ()
{
size_t buffer_size = 160000;
void* buffer = malloc (buffer_size);
hb_serialize_context_t c (buffer, buffer_size);
populate_serializer_with_overflow (&c);
graph_t graph (c.object_graph ());
assert (graph.will_overflow ());
}
int
main (int argc, char **argv)
{
test_serialize ();
test_sort_kahn_1 ();
test_sort_kahn_2 ();
test_will_overflow_1 ();
test_will_overflow_2 ();
}