diff --git a/src/hover.cpp b/src/hover.cpp index b7f9143..670b685 100644 --- a/src/hover.cpp +++ b/src/hover.cpp @@ -129,7 +129,7 @@ enum Hover_Section_Flags { // Functor used by get_section_hover_info to describe the structure of a section and print data about it. struct Sec_Hover_Fn { - u64 off; // the offset relative to the start of `data` + u64 off; // the hovered offset relative to the start of `data` const u8 *data; // the entire file data const Section §ion; Arena *arena; @@ -139,6 +139,17 @@ struct Sec_Hover_Fn { u8 cur_section_nesting = 0; u8 innermost_section_highlighted = 0; + template + b8 read(T *val, u64 offset, u64 *size = nullptr) const + { + u64 nb = size ? *size : sizeof(T); + if (offset + nb > section.range.end()) + return false; + + memcpy(val, data + offset, nb); + return true; + } + template void titled_section(const char *title, F &&sec_body_fn, u64 flags = 0) { @@ -186,7 +197,9 @@ struct Sec_Hover_Fn { b8 hovered = cur_field_off <= off && off < cur_field_off + field_len; T val; - memcpy(&val, (u8 *)data + cur_field_off, field_len); + if (!read(&val, cur_field_off)) + return false; + String8_Node *desc = display_val(arena, info.desc, desc_fmt, val); if (hovered && !display_grouped) info.highlighted_desc = desc; @@ -205,7 +218,9 @@ struct Sec_Hover_Fn { { // String size can be stored as different types, like u8 (by ROOT I/O) or u32 (by RNTuple). TStrSize str_size; - memcpy(&str_size, data + cur_field_off, sizeof(TStrSize)); + if (!read(&str_size, cur_field_off)) + return; + // DEBUG if (str_size > 1000) { printf("read str_size = %u at offset 0x%lX!\n", str_size, cur_field_off); @@ -215,7 +230,10 @@ struct Sec_Hover_Fn { b8 hovered = cur_field_off <= off && off < cur_field_off + field_len; u8 *buf = arena_push_array_nozero(arena, str_size + 1); - memcpy(buf, data + cur_field_off + sizeof(TStrSize), str_size); + u64 size_to_read = str_size; + if (!read(buf, cur_field_off + sizeof(TStrSize), &size_to_read)) + return; + buf[str_size] = 0; String8 s = { buf, str_size }; String8_Node *desc = display_val(arena, info.desc, desc_fmt, s); @@ -244,6 +262,8 @@ struct Sec_Hover_Fn { void range(const char *desc, u64 range_len, Display_Range_Fn display_val = hover_display_generic_range) { b8 hovered = cur_field_off <= off && off < cur_field_off + range_len; + if (cur_field_off + range_len > section.range.end()) + return; String8_Node *dsc = display_val(arena, info.desc, desc, data + cur_field_off, range_len); if (hovered && !display_grouped) info.highlighted_desc = dsc; @@ -257,13 +277,15 @@ struct Sec_Hover_Fn { // Returns true if `was_zipped` was read. b8 maybe_rootzip(b8 *was_zipped = nullptr) { - // TODO boundary checks const u64 range_len = 9; + if (cur_field_off + range_len > section.range.end()) + return false; + b8 hovered = cur_field_off <= off && off < cur_field_off + range_len; if (display_val_rootzip(arena, info.desc, "Zipped Block", data + cur_field_off)) { + if (was_zipped) + *was_zipped = true; if (display_grouped || hovered) { - if (was_zipped) - *was_zipped = true; info.rng = { cur_field_off, range_len }; if (hovered) info.highlighted_desc = info.desc; @@ -280,7 +302,9 @@ struct Sec_Hover_Fn { { titled_section(title, [this] { u16 version_be; - memcpy(&version_be, data + cur_field_off + 4, sizeof(u16)); + if (!read(&version_be, cur_field_off + 4)) + return; + u32 version = bswap(version_be); b8 is_big = version > 1000; @@ -318,7 +342,7 @@ struct Sec_Hover_Fn { range("Envelope size: %s", 6, [] (Arena *arena, String8_Node *prev, const char *fmt, const u8 *payload, u64) { u64 size; memcpy(&size, payload, 6); - return push_str8_node_child(arena, prev, fmt, to_pretty_size(arena, size)); + return push_str8_node_child(arena, prev, fmt, to_pretty_size(arena, size).c()); }); }); } @@ -335,7 +359,11 @@ struct Sec_Hover_Fn { Frame_Type frame_type = Frame_INVALID; titled_section(titlestr.c(), [this, &frame_type, &frame_size = size, n_items] { i64 size; - memcpy(&size, data + cur_field_off, sizeof(size)); + if (!read(&size, cur_field_off)) { + frame_size = 0; + frame_type = Frame_INVALID; + return; + } // Sanity check if (size > 1000000) { fprintf(stderr, "Frame size read at 0x%" PRIX64 " looks bogus" @@ -357,7 +385,11 @@ struct Sec_Hover_Fn { frame_type = Frame_INVALID; } else { frame_type = Frame_List; - memcpy(n_items, data + cur_field_off + sizeof(i64), sizeof(u32)); + if (!read(n_items, cur_field_off + sizeof(i64))) { + frame_size = 0; + frame_type = Frame_INVALID; + return; + } field("List frame size: %" PRIi64 " B", hover_display_val_le_abs); field_le("List frame n.items: %u"); } @@ -625,7 +657,8 @@ struct Sec_Hover_Fn { { titled_section("TFile Header", [this] { u32 root_version_be; - memcpy(&root_version_be, data + cur_field_off + 4, sizeof(u32)); + if (!read(&root_version_be, cur_field_off + 4)) + return; u32 root_version = bswap(root_version_be); b8 is_big = root_version > 1000'000; @@ -665,7 +698,8 @@ struct Sec_Hover_Fn { field_str8("File Title: %s"); u16 version_be; - memcpy(&version_be, data + cur_field_off, sizeof(u16)); + if (!read(&version_be, cur_field_off)) + return; u16 version = bswap(version_be); b8 is_big = version > 1000; @@ -721,7 +755,8 @@ struct Sec_Hover_Fn { titled_section("TFile FreeList", [this] { tkey(); u16 version_be; - memcpy(&version_be, data + cur_field_off, sizeof(u16)); + if (!read(&version_be, cur_field_off)) + return; u32 version = bswap(version_be); b8 is_big = version > 1000;