summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Hansson <andreas.hansson@arm.com>2015-12-17 17:07:11 -0500
committerAndreas Hansson <andreas.hansson@arm.com>2015-12-17 17:07:11 -0500
commit97887eb6dc9e548c9b5719727fd4783ef157917c (patch)
tree65b928581be0e6135b1c7b3ca1ffecf63059e3b2 /src
parent08754488a30da178effd0414f198462bf268d715 (diff)
downloadgem5-97887eb6dc9e548c9b5719727fd4783ef157917c.tar.xz
mem: Fix memory allocation bug in deferred snoop handling
This patch fixes a corner case in the deferred snoop handling, where requests ended up being used by multiple packets with different lifetimes, and inadvertently got deleted while they were still in use.
Diffstat (limited to 'src')
-rw-r--r--src/mem/cache/cache.cc12
-rw-r--r--src/mem/cache/mshr.cc37
2 files changed, 22 insertions, 27 deletions
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index 29919ccdf..67e889453 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -2005,15 +2005,9 @@ Cache::handleSnoop(PacketPtr pkt, CacheBlk *blk, bool is_timing,
}
if (!respond && is_timing && is_deferred) {
- // if it's a deferred timing snoop then we've made a copy of
- // both the request and the packet, and so if we're not using
- // those copies to respond and delete them here
- DPRINTF(Cache, "Deleting pkt %p and request %p for cmd %s addr: %p\n",
- pkt, pkt->req, pkt->cmdString(), pkt->getAddr());
-
- // the packets needs a response (just not from us), so we also
- // need to delete the request and not rely on the packet
- // destructor
+ // if it's a deferred timing snoop to which we are not
+ // responding, then we've made a copy of both the request and
+ // the packet, delete them here
assert(pkt->needsResponse());
delete pkt->req;
delete pkt;
diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc
index b58c256cd..1a97d5594 100644
--- a/src/mem/cache/mshr.cc
+++ b/src/mem/cache/mshr.cc
@@ -364,36 +364,37 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
if (isPendingDirty() || pkt->isInvalidate()) {
// We need to save and replay the packet in two cases:
// 1. We're awaiting an exclusive copy, so ownership is pending,
- // and we need to respond after we receive data.
+ // and we need to deal with the snoop after we receive data.
// 2. It's an invalidation (e.g., UpgradeReq), and we need
// to forward the snoop up the hierarchy after the current
// transaction completes.
-
- // Actual target device (typ. a memory) will delete the
- // packet on reception, so we need to save a copy here.
- // Clear flags and also allocate new data as the original
- // packet data storage may have been deleted by the time we
- // get to send this packet.
- PacketPtr cp_pkt = nullptr;
+ // Start by determining if we will eventually respond or not,
+ // matching the conditions checked in Cache::handleSnoop
+ bool will_respond = isPendingDirty() && pkt->needsResponse() &&
+ pkt->cmd != MemCmd::InvalidateReq;
+
+ // The packet we are snooping may be deleted by the time we
+ // actually process the target, and we consequently need to
+ // save a copy here. Clear flags and also allocate new data as
+ // the original packet data storage may have been deleted by
+ // the time we get to process this packet. In the cases where
+ // we are not responding after handling the snoop we also need
+ // to create a copy of the request to be on the safe side. In
+ // the latter case the cache is responsible for deleting both
+ // the packet and the request as part of handling the deferred
+ // snoop.
+ PacketPtr cp_pkt = will_respond ? new Packet(pkt, true, true) :
+ new Packet(new Request(*pkt->req), pkt->cmd);
if (isPendingDirty()) {
- // Case 1: The new packet will need to get the response from the
+ // The new packet will need to get the response from the
// MSHR already queued up here
- cp_pkt = new Packet(pkt, true, true);
pkt->assertMemInhibit();
// in the case of an uncacheable request there is no need
// to set the exclusive flag, but since the recipient does
// not care there is no harm in doing so
pkt->setSupplyExclusive();
- } else {
- // Case 2: We only need to buffer the packet for information
- // purposes; the original request can proceed without waiting
- // => Create a copy of the request, as that may get deallocated as
- // well
- cp_pkt = new Packet(new Request(*pkt->req), pkt->cmd);
- DPRINTF(Cache, "Copying packet %p -> %p and request %p -> %p\n",
- pkt, cp_pkt, pkt->req, cp_pkt->req);
}
targets.add(cp_pkt, curTick(), _order, Target::FromSnoop,
downstreamPending && targets.needsExclusive);