Skip to content

Commit

Permalink
Make shadow memory allocation-based rather than fragment-based.
Browse files Browse the repository at this point in the history
This is in preparation for bit-level initialization tracking
(mheinsen issue #9). This also simplifies the tracking of
initialization within allocations, though we do have to ensure
that allocations are added and removed correctly (and we never
try to set or clear the initialization of memory if the
allocation does not exist).

Note that this brings the tracing system's handling into line
with the replay system, which became allocation-based back in
commit 97b8557 !
  • Loading branch information
mheinsen committed Sep 11, 2016
1 parent e3c8da6 commit c9eec29
Show file tree
Hide file tree
Showing 21 changed files with 2,149 additions and 1,491 deletions.
104 changes: 65 additions & 39 deletions include/seec/Trace/TraceMemory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,58 @@
#define SEEC_TRACE_TRACEMEMORY_HPP

#include "seec/DSA/MemoryArea.hpp"
#include "seec/Trace/TraceFormat.hpp"
#include "seec/Util/Maybe.hpp"

#include <cassert>
#include <map>
#include <memory>
#include <vector>

namespace seec {

namespace trace {


/// \brief Trace information for an area of memory with state set by a single
/// event.
///
class TraceMemoryFragment {
/// The address and length of this fragment.
MemoryArea Area;
static constexpr char getUninitializedByte() { return ~0; }
static constexpr char getInitializedByte() { return 0; }

/// \brief Holds the shadow state for a memory allocation.
///
class TraceMemoryAllocation {
uintptr_t m_Address;

std::vector<char> m_Shadow;

public:
/// Construct a new fragment for a state.
TraceMemoryFragment(uintptr_t Address, std::size_t Length)
: Area(Address, Length)
/// \brief Construct a new MemoryAllocation.
TraceMemoryAllocation(uintptr_t const Address,
std::size_t const Length)
: m_Address(Address),
m_Shadow(/* count */ Length, /* value */ getUninitializedByte())
{}


/// \name Accessors
/// @{

MemoryArea &area() { return Area; }

MemoryArea const &area() const { return Area; }

/// @} (Accessors)

MemoryArea getArea() const { return MemoryArea(m_Address, getLength()); }

uintptr_t getAddress() const { return m_Address; }

std::size_t getLength() const { return m_Shadow.size(); }

char *getShadow() { return m_Shadow.data(); }

/// \name Mutators
/// @{
char *getShadowAt(uintptr_t const Address) {
assert(Address >= m_Address);
assert((Address - m_Address) < m_Shadow.size());
return m_Shadow.data() + (Address - m_Address);
}

void reposition(MemoryArea NewArea) {
Area = NewArea;
char const *getShadowAt(uintptr_t const Address) const {
assert(Address >= m_Address);
assert((Address - m_Address) < m_Shadow.size());
return m_Shadow.data() + (Address - m_Address);
}

/// @}
void resize(std::size_t const NewLength) {
m_Shadow.resize(NewLength, getUninitializedByte());
}
};


Expand All @@ -68,28 +77,35 @@ class TraceMemoryState {
TraceMemoryState(TraceMemoryState const &) = delete;
TraceMemoryState &operator=(TraceMemoryState const &) = delete;

/// Map from start addresses to memory fragments.
std::map<uintptr_t, TraceMemoryFragment> Fragments;
/// Map from start addresses to allocations.
std::map<uintptr_t, TraceMemoryAllocation> m_Allocations;

TraceMemoryAllocation *
getAllocationAtOrPreceding(uintptr_t const Address);

TraceMemoryAllocation const *
getAllocationAtOrPreceding(uintptr_t const Address) const;

TraceMemoryAllocation &getAllocationContaining(uintptr_t const Address,
std::size_t const Length);

TraceMemoryAllocation const &
getAllocationContaining(uintptr_t const Address,
std::size_t const Length) const;

public:
/// Construct a new, empty TraceMemoryState.
TraceMemoryState()
: Fragments()
: m_Allocations()
{}

/// \brief Add a new state and return overwritten states.
///
/// Add a new state record to the memory state, and return an ordered set
/// containing the offsets of all previous state records that were
/// overwritten (either partially or wholly). The offsets will be in
/// ascending order, which is equivalent to the order that the state events
/// occured in.
/// \brief Set all bytes in the given range to completely initialized.
///
/// \param Address start address of the updated memory.
/// \param Length number of bytes of updated memory.
void add(uintptr_t Address, std::size_t Length);

/// \brief Add a new memmove state and return overwritten states.
/// \brief Copy initialization of bytes in the given range.
///
/// \param Source start address of the source of the memmove.
/// \param Destination start address of the destination of the memmove.
Expand All @@ -98,17 +114,27 @@ class TraceMemoryState {
uintptr_t const Destination,
std::size_t const Size);

/// \brief Clear a section of memory and return the removed states.
/// \brief Set all bytes in the given range to be uninitialized.
///
void clear(uintptr_t Address, std::size_t Length);

/// \brief
/// \brief Check if all bytes in the range are completely initialized.
///
bool hasKnownState(uintptr_t Address, std::size_t Length) const;

/// \brief Find the length of initialized memory beginning at \c Address and
/// to a maximum length of \c MaxLength
///
size_t getLengthOfKnownState(uintptr_t Address, std::size_t MaxLength) const;

TraceMemoryAllocation const *
findAllocationContaining(uintptr_t const Address) const;

void addAllocation(uintptr_t const Address, std::size_t const Size);

void removeAllocation(uintptr_t const Address);

void resizeAllocation(uintptr_t const Address, std::size_t const NewSize);
};


Expand Down
11 changes: 1 addition & 10 deletions include/seec/Trace/TraceProcessListener.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,11 +518,6 @@ class TraceProcessListener {
return DynamicMemoryAllocations.count(Address);
}

/// \brief Get the \c DynamicAllocation at the given address.
///
DynamicAllocation *
getCurrentDynamicMemoryAllocation(uintptr_t const Address);

/// \brief Get the \c DynamicAllocation at the given address.
///
DynamicAllocation const *
Expand All @@ -538,11 +533,7 @@ class TraceProcessListener {
std::size_t Size);

/// Remove the dynamic memory allocation for an address.
bool removeCurrentDynamicMemoryAllocation(uintptr_t Address) {
std::lock_guard<std::mutex> Lock(DynamicMemoryAllocationsMutex);

return DynamicMemoryAllocations.erase(Address);
}
bool removeCurrentDynamicMemoryAllocation(uintptr_t Address);

/// @} (Dynamic memory allocation tracking)

Expand Down
2 changes: 2 additions & 0 deletions include/seec/Trace/TraceThreadListener.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ class TraceThreadListener

/// \brief Record a clear to a memory region.
///
/// Note this only records this clear, it does not perform it.
///
/// pre: GlobalMemoryLock acquired by this object.
///
void recordStateClear(uintptr_t Address, std::size_t Size);
Expand Down
3 changes: 2 additions & 1 deletion include/seec/Trace/TracedFunction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace seec {

namespace trace {

class TraceMemoryState;
class TraceThreadListener;


Expand Down Expand Up @@ -592,7 +593,7 @@ class TracedFunction {
/// \brief Restore a previous stack state.
/// \return area of memory that was invalidated by this stackrestore.
///
MemoryArea stackRestore(uintptr_t Key);
void stackRestore(uintptr_t Key, TraceMemoryState &TraceMemory);

/// @} (Mutators)
};
Expand Down
Loading

0 comments on commit c9eec29

Please sign in to comment.