Skip to content

Commit

Permalink
Heap Segments: Add support for detecting (badly) front padding suppor…
Browse files Browse the repository at this point in the history
…t in all the heap segment type allocations

Changes:
* Remove old front heap padding detection / matching
* Add front padding detection code into segment_heap_utils
* Add front padding support into heap_lfh_entry, heap_vs_entry and large_alloc_entry
* Fix returning invalid lfh_segment by detecting that there is at least one valid heap_lfh_entry available
* Add front padding output to segment heap dumping
* Fix some MSVC diagnostic warnings
  • Loading branch information
shanepowell committed Aug 27, 2022
1 parent 0ac388d commit 0a4d6b6
Show file tree
Hide file tree
Showing 22 changed files with 180 additions and 60 deletions.
1 change: 1 addition & 0 deletions DbgHelpUtils.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Classes_0020and_0020structs/@EntryIndexedValue">&lt;NamingElement Priority="1"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="__interface" /&gt;&lt;type Name="class" /&gt;&lt;type Name="struct" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Class_0020and_0020struct_0020methods/@EntryIndexedValue">&lt;NamingElement Priority="9"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="member function" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/NamingElement&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=acrt/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=anyofallof/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=bugprone/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=chrono/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=cppcoreguidelines/@EntryIndexedValue">True</s:Boolean>
Expand Down
2 changes: 1 addition & 1 deletion DbgHelpUtils/heap_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ namespace dlg_help_utils::heap
[[nodiscard]] size_units::base_16::bytes unused_bytes() const { return unused_bytes_; }
[[nodiscard]] size_units::base_16::bytes ust_unused_bytes_raw() const;
[[nodiscard]] size_units::base_16::bytes data_area_max_size() const;
[[nodiscard]] std::optional<size_units::base_16::bytes> eod() const { return eod_; }
[[nodiscard]] std::optional<size_units::base_16::bytes> const& eod() const { return eod_; }
[[nodiscard]] uint64_t ust_header_address() const { return ust_header_address_; }
[[nodiscard]] std::optional<size_units::base_16::bytes> const& ust_end_gap_length() const { return ust_end_gap_length_; }

Expand Down
10 changes: 8 additions & 2 deletions DbgHelpUtils/heap_lfh_entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace dlg_help_utils::heap
, allocated_{allocated}
, has_unused_bytes_{has_unused_bytes}
, unused_bytes_{get_unused_bytes()}
, front_padding_size_{get_front_padding_size()}
, ust_address_{get_ust_address()}
, allocation_stack_trace_{get_allocation_stack_trace()}
{
Expand All @@ -31,12 +32,12 @@ namespace dlg_help_utils::heap

uint64_t heap_lfh_entry::user_address() const
{
return heap_lfh_entry_address();
return heap_lfh_entry_address() + front_padding_size().value_or(0);
}

size_units::base_16::bytes heap_lfh_entry::user_requested_size() const
{
return size_units::base_16::bytes{block_size().count() - unused_bytes().count()};
return size_units::base_16::bytes{block_size().count() - unused_bytes().count() - front_padding_size().value_or(0)};
}

size_units::base_16::bytes heap_lfh_entry::get_unused_bytes() const
Expand All @@ -63,4 +64,9 @@ namespace dlg_help_utils::heap
{
return heap().stack_trace().read_allocation_stack_trace(peb(), ust_address());
}

std::optional<uint64_t> heap_lfh_entry::get_front_padding_size() const
{
return segment_heap_utils::read_front_padding_size(peb(), heap_lfh_entry_address(), block_size().count());
}
}
6 changes: 5 additions & 1 deletion DbgHelpUtils/heap_lfh_entry.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <optional>

#include "size_units.h"
#include "tagged_bool.h"
Expand Down Expand Up @@ -36,6 +37,7 @@ namespace dlg_help_utils::heap
[[nodiscard]] bool allocated() const { return static_cast<bool>(allocated_); }
[[nodiscard]] bool has_unused_bytes() const { return static_cast<bool>(has_unused_bytes_); }
[[nodiscard]] size_units::base_16::bytes unused_bytes() const { return unused_bytes_; }
[[nodiscard]] std::optional<uint64_t> const& front_padding_size() const { return front_padding_size_; }

[[nodiscard]] uint64_t block_address() const { return heap_lfh_entry_address(); }
[[nodiscard]] uint64_t user_address() const;
Expand All @@ -48,6 +50,7 @@ namespace dlg_help_utils::heap
[[nodiscard]] size_units::base_16::bytes get_unused_bytes() const;
[[nodiscard]] uint64_t get_ust_address() const;
[[nodiscard]] std::vector<uint64_t> get_allocation_stack_trace() const;
[[nodiscard]] std::optional<uint64_t> get_front_padding_size() const;

private:
heap_lfh_context const* heap_;
Expand All @@ -56,7 +59,8 @@ namespace dlg_help_utils::heap
allocated_t allocated_;
has_unused_bytes_t has_unused_bytes_;
size_units::base_16::bytes unused_bytes_;
uint64_t ust_address_{0};
std::optional<uint64_t> front_padding_size_;
uint64_t ust_address_;
std::vector<uint64_t> allocation_stack_trace_{};
};
}
Expand Down
28 changes: 1 addition & 27 deletions DbgHelpUtils/heap_match_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@

namespace dlg_help_utils::heap
{
namespace
{
// assume front padding never goes above this size...
// this is a made up value as I have never see the front end padding to be very large
uint64_t constexpr maximum_front_crt_heap_memory_padding = 1024;
}

block_range_match_result heap_match_utils::does_memory_match_to_range(stream_stack_dump::mini_dump_memory_walker const& walker
, uint64_t const user_address
block_range_match_result heap_match_utils::does_memory_match_to_range(uint64_t const user_address
, size_units::base_16::bytes const user_size
, uint64_t const block_address
, size_units::base_16::bytes const block_size)
Expand All @@ -22,12 +14,6 @@ namespace dlg_help_utils::heap
return block_range_match_result::block_match;
}

if(auto const front_padding_size = read_front_padding_size(walker, block_address, block_size);
user_address == block_address + front_padding_size && user_size == block_size - size_units::base_16::bytes{front_padding_size})
{
return block_range_match_result::block_match;
}

if(user_address >= block_address && user_address + user_size.count() <= block_address + block_size.count())
{
return block_range_match_result::block_contains;
Expand All @@ -45,16 +31,4 @@ namespace dlg_help_utils::heap

return block_range_match_result::block_no_match;
}

uint64_t heap_match_utils::read_front_padding_size(stream_stack_dump::mini_dump_memory_walker const& walker, uint64_t const block_address, size_units::base_16::bytes const block_size)
{
auto const value = stream_utils::read_field_value<uint32_t>(walker, block_address).value_or(0);
if(value >= block_size.count() ||
value > maximum_front_crt_heap_memory_padding)
{
return 0;
}

return value;
}
}
4 changes: 1 addition & 3 deletions DbgHelpUtils/heap_match_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ namespace dlg_help_utils::heap
class heap_match_utils
{
public:
static [[nodiscard]] block_range_match_result does_memory_match_to_range(stream_stack_dump::mini_dump_memory_walker const& walker
, uint64_t user_address
static [[nodiscard]] block_range_match_result does_memory_match_to_range(uint64_t user_address
, size_units::base_16::bytes user_size
, uint64_t block_address
, size_units::base_16::bytes block_size);
static [[nodiscard]] uint64_t read_front_padding_size(stream_stack_dump::mini_dump_memory_walker const& walker, uint64_t block_address, size_units::base_16::bytes block_size);
};
}
7 changes: 5 additions & 2 deletions DbgHelpUtils/heap_subsegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ namespace dlg_help_utils::heap
break;
}

heap_entry entry{lfh_heap().heap(), address, std::move(buffer), block_size_value, heap_entry::LfhEntryType{}};
co_yield entry;
if(heap_entry entry{lfh_heap().heap(), address, std::move(buffer), block_size_value, heap_entry::LfhEntryType{}};
entry.is_lfh_entry())
{
co_yield entry;
}

address += block_stride_;
}
Expand Down
18 changes: 15 additions & 3 deletions DbgHelpUtils/heap_vs_entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace dlg_help_utils::heap
, heap_{&heap}
, heap_vs_entry_address_{heap_vs_entry_address}
, buffer_{std::move(buffer)}
, front_padding_size_{get_front_padding_size()}
, size_{get_size()}
, previous_size_{get_previous_size()}
, is_valid_{get_is_valid(previous_size)}
Expand All @@ -31,6 +32,7 @@ namespace dlg_help_utils::heap
, heap_{&heap}
, heap_vs_entry_address_{heap_vs_entry_address}
, buffer_{std::move(buffer)}
, front_padding_size_{get_front_padding_size()}
, size_{get_size()}
, previous_size_{get_previous_size()}
, ust_address_{get_ust_address()}
Expand Down Expand Up @@ -121,12 +123,12 @@ namespace dlg_help_utils::heap

uint64_t heap_vs_entry::user_address() const
{
return block_address();
return block_address() + front_padding_size().value_or(0);
}

size_units::base_16::bytes heap_vs_entry::user_requested_size() const
{
auto requested_user_size = block_size();
auto requested_user_size = block_size() - front_padding_size().value_or(0);

if(has_unused_bytes())
{
Expand Down Expand Up @@ -167,9 +169,14 @@ namespace dlg_help_utils::heap
}
}

std::optional<uint64_t> heap_vs_entry::get_front_padding_size() const
{
return segment_heap_utils::read_front_padding_size(peb(), block_address(), block_size());
}

size_units::base_16::bytes heap_vs_entry::get_size() const
{
return size_units::base_16::bytes{raw_size() << heap().unit_shift_amount()};
return size_units::base_16::bytes{raw_full_size()};
}

size_units::base_16::bytes heap_vs_entry::get_previous_size() const
Expand Down Expand Up @@ -203,6 +210,11 @@ namespace dlg_help_utils::heap
return heap().stack_trace().read_allocation_stack_trace(peb(), ust_address());
}

uint64_t heap_vs_entry::raw_full_size() const
{
return static_cast<uint64_t>(raw_size()) << heap().unit_shift_amount();
}

void heap_vs_entry::validate_buffer() const
{
if(!buffer_)
Expand Down
4 changes: 4 additions & 0 deletions DbgHelpUtils/heap_vs_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace dlg_help_utils::heap
[[nodiscard]] bool skip_during_walk() const;
[[nodiscard]] uint32_t spare() const;
[[nodiscard]] uint32_t allocated_chunk_bits() const;
[[nodiscard]] std::optional<uint64_t> const& front_padding_size() const { return front_padding_size_; }

[[nodiscard]] uint64_t block_address() const;
[[nodiscard]] uint64_t block_size() const;
Expand All @@ -65,12 +66,14 @@ namespace dlg_help_utils::heap
static void setup_globals(segment_heap const& heap);

private:
[[nodiscard]] std::optional<uint64_t> get_front_padding_size() const;
[[nodiscard]] size_units::base_16::bytes get_size() const;
[[nodiscard]] size_units::base_16::bytes get_previous_size() const;
[[nodiscard]] uint16_t get_previous_size_raw() const;
[[nodiscard]] bool get_is_valid(uint16_t previous_size) const;
[[nodiscard]] uint64_t get_ust_address() const;
[[nodiscard]] std::vector<uint64_t> get_allocation_stack_trace() const;
[[nodiscard]] uint64_t raw_full_size() const;
void validate_buffer() const;

private:
Expand All @@ -95,6 +98,7 @@ namespace dlg_help_utils::heap
segment_heap const* heap_;
uint64_t heap_vs_entry_address_;
std::unique_ptr<uint8_t[]> buffer_;
std::optional<uint64_t> front_padding_size_;
size_units::base_16::bytes size_;
size_units::base_16::bytes previous_size_{0};
bool is_valid_{true};
Expand Down
10 changes: 8 additions & 2 deletions DbgHelpUtils/large_alloc_entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace dlg_help_utils::heap
, heap_{&heap}
, large_alloc_entry_address_{large_alloc_entry_address}
, size_{get_size()}
, front_padding_size_{get_front_padding_size()}
, ust_address_{get_ust_address()}
, allocation_stack_trace_{get_allocation_stack_trace()}
{
Expand Down Expand Up @@ -77,12 +78,12 @@ namespace dlg_help_utils::heap

uint64_t large_alloc_entry::user_address() const
{
return block_address();
return block_address() + front_padding_size().value_or(0);
}

size_units::base_16::bytes large_alloc_entry::user_requested_size() const
{
return size_units::base_16::bytes{block_size() - unused_bytes().count()};
return size_units::base_16::bytes{block_size() - unused_bytes().count() - front_padding_size().value_or(0)};
}

void large_alloc_entry::setup_globals(segment_heap const& heap)
Expand All @@ -109,6 +110,11 @@ namespace dlg_help_utils::heap
return size_units::base_16::bytes{allocated_pages() * heap().peb().page_size()};
}

std::optional<uint64_t> large_alloc_entry::get_front_padding_size() const
{
return segment_heap_utils::read_front_padding_size_large(peb(), block_address(), block_size());
}

uint64_t large_alloc_entry::get_ust_address() const
{
if(!peb().user_stack_db_enabled() || !extra_present())
Expand Down
3 changes: 3 additions & 0 deletions DbgHelpUtils/large_alloc_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace dlg_help_utils::heap
[[nodiscard]] uint64_t block_size() const;
[[nodiscard]] uint64_t user_address() const;
[[nodiscard]] size_units::base_16::bytes user_requested_size() const;
[[nodiscard]] std::optional<uint64_t> const& front_padding_size() const { return front_padding_size_; }

[[nodiscard]] uint64_t ust_address() const { return ust_address_; }
[[nodiscard]] std::vector<uint64_t> const& allocation_stack_trace() const { return allocation_stack_trace_; }
Expand All @@ -57,6 +58,7 @@ namespace dlg_help_utils::heap

private:
[[nodiscard]] size_units::base_16::bytes get_size() const;
[[nodiscard]] std::optional<uint64_t> get_front_padding_size() const;
[[nodiscard]] uint64_t get_ust_address() const;
[[nodiscard]] std::vector<uint64_t> get_allocation_stack_trace() const;

Expand All @@ -80,6 +82,7 @@ namespace dlg_help_utils::heap
segment_heap const* heap_;
uint64_t large_alloc_entry_address_;
size_units::base_16::bytes size_;
std::optional<uint64_t> front_padding_size_;
uint64_t ust_address_{0};
std::vector<uint64_t> allocation_stack_trace_{};
};
Expand Down
17 changes: 16 additions & 1 deletion DbgHelpUtils/lfh_segment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ namespace dlg_help_utils::heap
return stream_utils::get_type_length(cache.lfh_block_zone_symbol_type, symbol_name);
}

bool lfh_segment::has_any_entries(heap_subsegment const& subsegment)
{
for (auto const& entry : subsegment.entries()) // NOLINT(readability-use-anyofallof)
{
if(entry.is_lfh_entry())
{
return true;
}
}

return false;
}

std::vector<heap_subsegment> lfh_segment::build_subsegments() const
{
// filter out non-valid lfh segments, segments that are not in a HEAP internal allocated entry
Expand All @@ -123,7 +136,9 @@ namespace dlg_help_utils::heap
}

if(heap_subsegment subsegment{lfh_heap(), subsegment_address, cache_data_->lfh_block_zone_size};
subsegment.entry_start_address() != 0 && std::ranges::any_of(all_heap_entries, [&subsegment](heap_entry const& entry) { return process_heaps::is_lfh_subsegment_in_entry(entry, subsegment); }))
subsegment.entry_start_address() != 0
&& std::ranges::any_of(all_heap_entries, [&subsegment](heap_entry const& entry) { return process_heaps::is_lfh_subsegment_in_entry(entry, subsegment); })
&& has_any_entries(subsegment))
{
rv.emplace_back(subsegment);
}
Expand Down
3 changes: 2 additions & 1 deletion DbgHelpUtils/lfh_segment.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ namespace dlg_help_utils::heap
std::optional<stream_utils::symbol_type_and_base_type_field_offset> lfh_block_zone_free_pointer_field_data;
};

[[nodiscard]] std::pair<uint64_t, uint64_t> get_subsegment_range() const;
std::pair<uint64_t, uint64_t> get_subsegment_range() const;
[[nodiscard]] std::vector<heap_subsegment> build_subsegments() const;

[[nodiscard]] static size_t get_lfh_block_zone_size(cache_data const& cache, nt_heap const& heap);
[[nodiscard]] static bool has_any_entries(heap_subsegment const& subsegment);

private:
cache_data const* cache_data_;
Expand Down
12 changes: 9 additions & 3 deletions DbgHelpUtils/page_range_descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace dlg_help_utils::heap
, index_{index}
, heap_page_segment_address_{heap_page_segment_address}
, unit_shift_{heap.unit_shift()}
, front_padding_size_{get_front_padding_size()}
, ust_address_{get_ust_address()}
, allocation_stack_trace_{get_allocation_stack_trace()}
{
Expand Down Expand Up @@ -101,7 +102,7 @@ namespace dlg_help_utils::heap

uint64_t page_range_descriptor::user_address() const
{
return block_address();
return block_address() + front_padding_size().value_or(0);
}

size_units::base_16::bytes page_range_descriptor::block_size() const
Expand All @@ -116,10 +117,10 @@ namespace dlg_help_utils::heap

if(extra >= size)
{
return size_units::base_16::bytes{size};
return size_units::base_16::bytes{size - front_padding_size().value_or(0)};
}

return size_units::base_16::bytes{size - extra};
return size_units::base_16::bytes{size - extra - front_padding_size().value_or(0)};
}

bool page_range_descriptor::is_start_of_range() const
Expand Down Expand Up @@ -152,6 +153,11 @@ namespace dlg_help_utils::heap
}
}

std::optional<uint64_t> page_range_descriptor::get_front_padding_size() const
{
return segment_heap_utils::read_front_padding_size(peb(), block_address(), block_size().count());
}

uint64_t page_range_descriptor::get_ust_address() const
{
if(!peb().user_stack_db_enabled() || !extra_present())
Expand Down
Loading

0 comments on commit 0a4d6b6

Please sign in to comment.