Gabriel B. has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/67452?usp=email )

Change subject: mem-ruby: Fix nullptr deref with base Port classes
......................................................................

mem-ruby: Fix nullptr deref with base Port classes

Change-Id: I29214278c3dd4829c89a6f7c93214b8123912e74
---
M src/arch/arm/table_walker.cc
M src/cpu/simple/atomic.cc
M src/mem/cache/base.cc
M src/mem/port.cc
M src/mem/port.hh
M src/mem/ruby/system/RubyPort.cc
M src/sim/port.cc
M src/sim/port.hh
8 files changed, 106 insertions(+), 64 deletions(-)



diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc
index bbf102d..8e16e9b 100644
--- a/src/arch/arm/table_walker.cc
+++ b/src/arch/arm/table_walker.cc
@@ -234,7 +234,7 @@
                               Addr size, Tick delay)
 {
     if (state->event) {
-        owner.schedule(state->event, curTick() + delay);
+        owner().schedule(state->event, curTick() + delay);
     }
     delete state;
 }
diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc
index d6638b3..770bbf4 100644
--- a/src/cpu/simple/atomic.cc
+++ b/src/cpu/simple/atomic.cc
@@ -281,7 +281,7 @@
             __func__, pkt->getAddr(), pkt->cmdString());

     // X86 ISA: Snooping an invalidation for monitor/mwait
-    AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
+    AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner());

     for (ThreadID tid = 0; tid < cpu->numThreads; tid++) {
         if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) {
@@ -312,7 +312,7 @@
             __func__, pkt->getAddr(), pkt->cmdString());

     // X86 ISA: Snooping an invalidation for monitor/mwait
-    AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner);
+    AtomicSimpleCPU *cpu = (AtomicSimpleCPU *)(&owner());
     for (ThreadID tid = 0; tid < cpu->numThreads; tid++) {
         if (cpu->getCpuAddrMonitor(tid)->doMonitor(pkt)) {
             cpu->wakeup(tid);
diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc
index cf6c9fe..cbf4bea 100644
--- a/src/mem/cache/base.cc
+++ b/src/mem/cache/base.cc
@@ -150,7 +150,7 @@
     // if we already scheduled a retry in this cycle, but it has not yet
     // happened, cancel it
     if (sendRetryEvent.scheduled()) {
-        owner.deschedule(sendRetryEvent);
+        owner().deschedule(sendRetryEvent);
         DPRINTF(CachePort, "Port descheduled retry\n");
         mustSendRetry = true;
     }
@@ -164,7 +164,7 @@
     blocked = false;
     if (mustSendRetry) {
         // @TODO: need to find a better time (next cycle?)
-        owner.schedule(sendRetryEvent, curTick() + 1);
+        owner().schedule(sendRetryEvent, curTick() + 1);
     }
 }

diff --git a/src/mem/port.cc b/src/mem/port.cc
index 18793d4..316a76a 100644
--- a/src/mem/port.cc
+++ b/src/mem/port.cc
@@ -121,8 +121,7 @@
  * Request port
  */
 RequestPort::RequestPort(const std::string& name, SimObject* _owner,
-    PortID _id) : Port(name, _id), _responsePort(&defaultResponsePort),
-    owner(*_owner)
+ PortID _id) : Port(name, _owner, _id), _responsePort(&defaultResponsePort)
 {
 }

@@ -176,8 +175,8 @@
  * Response port
  */
 ResponsePort::ResponsePort(const std::string& name, SimObject* _owner,
-    PortID id) : Port(name, id), _requestPort(&defaultRequestPort),
-    defaultBackdoorWarned(false), owner(*_owner)
+    PortID id) : Port(name, _owner, id), _requestPort(&defaultRequestPort),
+    defaultBackdoorWarned(false)
 {
 }

diff --git a/src/mem/port.hh b/src/mem/port.hh
index fb0f4b8..fe5a12a 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -82,9 +82,6 @@
   private:
     ResponsePort *_responsePort;

-  protected:
-    SimObject &owner;
-
   public:
     RequestPort(const std::string& name, SimObject* _owner,
                PortID id=InvalidPortID);
@@ -290,9 +287,6 @@

     bool defaultBackdoorWarned;

-  protected:
-    SimObject& owner;
-
   public:
     ResponsePort(const std::string& name, SimObject* _owner,
               PortID id=InvalidPortID);
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index 48f655d..28055e2 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -171,12 +171,12 @@
 bool
 RubyPort::PioRequestPort::recvTimingResp(PacketPtr pkt)
 {
-    RubyPort *rp = static_cast<RubyPort *>(&owner);
+    RubyPort& rp = safe_cast<RubyPort&>(owner());
     DPRINTF(RubyPort, "Response for address: 0x%#x\n", pkt->getAddr());

     // send next cycle
-    rp->pioResponsePort.schedTimingResp(
-            pkt, curTick() + rp->m_ruby_system->clockPeriod());
+    rp.pioResponsePort.schedTimingResp(
+            pkt, curTick() + rp.m_ruby_system->clockPeriod());
     return true;
 }

@@ -199,8 +199,8 @@
             pkt->getAddr(), port->name());

     // attempt to send the response in the next cycle
-    RubyPort *rp = static_cast<RubyPort *>(&owner);
- port->schedTimingResp(pkt, curTick() + rp->m_ruby_system->clockPeriod());
+    RubyPort& rp = safe_cast<RubyPort&>(owner());
+ port->schedTimingResp(pkt, curTick() + rp.m_ruby_system->clockPeriod());

     return true;
 }
@@ -208,16 +208,16 @@
 bool
 RubyPort::PioResponsePort::recvTimingReq(PacketPtr pkt)
 {
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    auto& ruby_port = safe_cast<RubyPort&>(owner());

-    for (size_t i = 0; i < ruby_port->request_ports.size(); ++i) {
-        AddrRangeList l = ruby_port->request_ports[i]->getAddrRanges();
+    for (size_t i = 0; i < ruby_port.request_ports.size(); ++i) {
+        AddrRangeList l = ruby_port.request_ports[i]->getAddrRanges();
         for (auto it = l.begin(); it != l.end(); ++it) {
             if (it->contains(pkt->getAddr())) {
                 // generally it is not safe to assume success here as
                 // the port could be blocked
                 [[maybe_unused]] bool success =
-                    ruby_port->request_ports[i]->sendTimingReq(pkt);
+                    ruby_port.request_ports[i]->sendTimingReq(pkt);
                 assert(success);
                 return true;
             }
@@ -229,17 +229,17 @@
 Tick
 RubyPort::PioResponsePort::recvAtomic(PacketPtr pkt)
 {
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    auto& ruby_port = safe_cast<RubyPort&>(owner());
     // Only atomic_noncaching mode supported!
-    if (!ruby_port->system->bypassCaches()) {
+    if (!ruby_port.system->bypassCaches()) {
         panic("Ruby supports atomic accesses only in noncaching mode\n");
     }

-    for (size_t i = 0; i < ruby_port->request_ports.size(); ++i) {
-        AddrRangeList l = ruby_port->request_ports[i]->getAddrRanges();
+    for (size_t i = 0; i < ruby_port.request_ports.size(); ++i) {
+        AddrRangeList l = ruby_port.request_ports[i]->getAddrRanges();
         for (auto it = l.begin(); it != l.end(); ++it) {
             if (it->contains(pkt->getAddr())) {
-                return ruby_port->request_ports[i]->sendAtomic(pkt);
+                return ruby_port.request_ports[i]->sendAtomic(pkt);
             }
         }
     }
@@ -251,7 +251,7 @@
 {
     DPRINTF(RubyPort, "Timing request for address %#x on port %d\n",
             pkt->getAddr(), id);
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    auto& ruby_port = safe_cast<RubyPort&>(owner());

     if (pkt->cacheResponding())
         panic("RubyPort should never see request with the "
@@ -269,7 +269,7 @@
     // pio port.
     if (pkt->cmd != MemCmd::MemSyncReq) {
         if (!pkt->req->isMemMgmt() && !isPhysMemAddress(pkt)) {
-            assert(ruby_port->memRequestPort.isConnected());
+            assert(ruby_port.memRequestPort.isConnected());
             DPRINTF(RubyPort, "Request address %#x assumed to be a "
                     "pio address\n", pkt->getAddr());

@@ -278,8 +278,8 @@
             pkt->pushSenderState(new SenderState(this));

             // send next cycle
-            RubySystem *rs = ruby_port->m_ruby_system;
-            ruby_port->memRequestPort.schedTimingReq(pkt,
+            RubySystem *rs = ruby_port.m_ruby_system;
+            ruby_port.memRequestPort.schedTimingReq(pkt,
                 curTick() + rs->clockPeriod());
             return true;
         }
@@ -290,7 +290,7 @@
     pkt->pushSenderState(new SenderState(this));

     // Submit the ruby request
-    RequestStatus requestStatus = ruby_port->makeRequest(pkt);
+    RequestStatus requestStatus = ruby_port.makeRequest(pkt);

     // If the request successfully issued then we should return true.
     // Otherwise, we need to tell the port to retry at a later point
@@ -320,9 +320,9 @@
 Tick
 RubyPort::MemResponsePort::recvAtomic(PacketPtr pkt)
 {
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    auto& ruby_port = safe_cast<RubyPort&>(owner());
     // Only atomic_noncaching mode supported!
-    if (!ruby_port->system->bypassCaches()) {
+    if (!ruby_port.system->bypassCaches()) {
         panic("Ruby supports atomic accesses only in noncaching mode\n");
     }

@@ -330,7 +330,7 @@
     // pio port.
     if (pkt->cmd != MemCmd::MemSyncReq) {
         if (!isPhysMemAddress(pkt)) {
-            assert(ruby_port->memRequestPort.isConnected());
+            assert(ruby_port.memRequestPort.isConnected());
             DPRINTF(RubyPort, "Request address %#x assumed to be a "
                     "pio address\n", pkt->getAddr());

@@ -339,8 +339,8 @@
             pkt->pushSenderState(new SenderState(this));

             // send next cycle
-            Tick req_ticks = ruby_port->memRequestPort.sendAtomic(pkt);
-            return ruby_port->ticksToCycles(req_ticks);
+            Tick req_ticks = ruby_port.memRequestPort.sendAtomic(pkt);
+            return ruby_port.ticksToCycles(req_ticks);
         }

         assert(getOffset(pkt->getAddr()) + pkt->getSize() <=
@@ -348,7 +348,7 @@
     }

     // Find the machine type of memory controller interface
-    RubySystem *rs = ruby_port->m_ruby_system;
+    RubySystem *rs = ruby_port.m_ruby_system;
     static int mem_interface_type = -1;
     if (mem_interface_type == -1) {
         if (rs->m_abstract_controls[MachineType_Directory].size() != 0) {
@@ -363,7 +363,7 @@
     }

     // Find the controller for the target address
-    MachineID id = ruby_port->m_controller->mapAddressToMachine(
+    MachineID id = ruby_port.m_controller->mapAddressToMachine(
                     pkt->getAddr(), (MachineType)mem_interface_type);
     AbstractController *mem_interface =
         rs->m_abstract_controls[mem_interface_type][id.getNum()];
@@ -376,15 +376,15 @@
 void
 RubyPort::MemResponsePort::addToRetryList()
 {
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    auto& ruby_port = safe_cast<RubyPort&>(owner());

     //
     // Unless the request port do not want retries (e.g., the Ruby tester),
     // record the stalled M5 port for later retry when the sequencer
     // becomes free.
     //
-    if (!no_retry_on_stall && !ruby_port->onRetryList(this)) {
-        ruby_port->addToRetryList(this);
+    if (!no_retry_on_stall && !ruby_port.onRetryList(this)) {
+        ruby_port.addToRetryList(this);
     }
 }

@@ -393,15 +393,15 @@
 {
DPRINTF(RubyPort, "Functional access for address: %#x\n", pkt->getAddr());

-    [[maybe_unused]] RubyPort *rp = static_cast<RubyPort *>(&owner);
-    RubySystem *rs = rp->m_ruby_system;
+    [[maybe_unused]] RubyPort& rp = safe_cast<RubyPort&>(owner());
+    RubySystem *rs = rp.m_ruby_system;

     // Check for pio requests and directly send them to the dedicated
     // pio port.
     if (!isPhysMemAddress(pkt)) {
DPRINTF(RubyPort, "Pio Request for address: 0x%#x\n", pkt->getAddr());
-        assert(rp->pioRequestPort.isConnected());
-        rp->pioRequestPort.sendFunctional(pkt);
+        assert(rp.pioRequestPort.isConnected());
+        rp.pioRequestPort.sendFunctional(pkt);
         return;
     }

@@ -626,15 +626,15 @@

     DPRINTF(RubyPort, "Hit callback needs response %d\n", needsResponse);

-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
-    RubySystem *rs = ruby_port->m_ruby_system;
+    auto& ruby_port = safe_cast<RubyPort&>(owner());
+    RubySystem *rs = ruby_port.m_ruby_system;
     if (accessPhysMem) {
         // We must check device memory first in case it overlaps with the
         // system memory range.
-        if (ruby_port->system->isDeviceMemAddr(pkt)) {
-            auto dmem = ruby_port->system->getDeviceMemory(pkt);
+        if (ruby_port.system->isDeviceMemAddr(pkt)) {
+            auto dmem = ruby_port.system->getDeviceMemory(pkt);
             dmem->access(pkt);
-        } else if (ruby_port->system->isMemAddr(pkt->getAddr())) {
+        } else if (ruby_port.system->isMemAddr(pkt->getAddr())) {
             rs->getPhysMem()->access(pkt);
         } else {
             panic("Packet is in neither device nor system memory!");
@@ -662,11 +662,11 @@
 {
     // at the moment the assumption is that the request port does not care
     AddrRangeList ranges;
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    auto& ruby_port = safe_cast<RubyPort const&>(owner());

-    for (size_t i = 0; i < ruby_port->request_ports.size(); ++i) {
+    for (size_t i = 0; i < ruby_port.request_ports.size(); ++i) {
         ranges.splice(ranges.begin(),
-                ruby_port->request_ports[i]->getAddrRanges());
+                ruby_port.request_ports[i]->getAddrRanges());
     }
     for ([[maybe_unused]] const auto &r : ranges)
         DPRINTF(RubyPort, "%s\n", r.to_string());
@@ -676,8 +676,8 @@
 bool
 RubyPort::MemResponsePort::isShadowRomAddress(Addr addr) const
 {
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
-    AddrRangeList ranges = ruby_port->system->getShadowRomRanges();
+    auto& ruby_port = safe_cast<RubyPort const&>(owner());
+    AddrRangeList ranges = ruby_port.system->getShadowRomRanges();

     for (auto it = ranges.begin(); it != ranges.end(); ++it) {
         if (it->contains(addr)) {
@@ -691,10 +691,10 @@
 bool
 RubyPort::MemResponsePort::isPhysMemAddress(PacketPtr pkt) const
 {
-    RubyPort *ruby_port = static_cast<RubyPort *>(&owner);
+    auto& ruby_port = safe_cast<RubyPort const&>(owner());
     Addr addr = pkt->getAddr();
- return (ruby_port->system->isMemAddr(addr) && !isShadowRomAddress(addr))
-           || ruby_port->system->isDeviceMemAddr(pkt);
+    return (ruby_port.system->isMemAddr(addr) && !isShadowRomAddress(addr))
+           || ruby_port.system->isDeviceMemAddr(pkt);
 }

 void
@@ -724,7 +724,7 @@
 void
 RubyPort::PioRequestPort::recvRangeChange()
 {
-    RubyPort &r = static_cast<RubyPort &>(owner);
+    RubyPort &r = static_cast<RubyPort &>(owner());
     r.gotAddrRanges--;
     if (r.gotAddrRanges == 0 && FullSystem) {
         r.pioResponsePort.sendRangeChange();
diff --git a/src/sim/port.cc b/src/sim/port.cc
index 580469a..37ffe72 100644
--- a/src/sim/port.cc
+++ b/src/sim/port.cc
@@ -50,11 +50,32 @@
 namespace gem5
 {

-Port::Port(const std::string& _name, PortID _id) :
-    portName(_name), id(_id), _peer(nullptr), _connected(false)
+Port::Port(const std::string& _name, SimObject* owner, PortID _id) :
+    portName{_name},
+    portOwner{owner},
+    id{_id},
+    _peer{nullptr},
+    _connected{false}
 {}
+
+Port::Port(const std::string& _name, PortID _id) :
+    Port{_name, nullptr, _id}
+{}
+
 Port::~Port() {}

+SimObject&
+Port::owner()
+{
+    return const_cast<SimObject&>(const_cast<const Port*>(this)->owner());
+}
+
+SimObject const&
+Port::owner() const
+{
+    panic_if(!portOwner, "Requesting owner of ownerless port.");
+    return *portOwner;
+}

 void
 Port::reportUnbound() const
diff --git a/src/sim/port.hh b/src/sim/port.hh
index 4f4a163..2b5b759 100644
--- a/src/sim/port.hh
+++ b/src/sim/port.hh
@@ -55,6 +55,8 @@
 namespace gem5
 {

+class SimObject;
+
 /**
  * Ports are used to interface objects to each other.
  */
@@ -66,6 +68,8 @@
     /** Descriptive name (for DPRINTF output) */
     const std::string portName;

+    SimObject* portOwner;
+
   protected:

     class UnboundPortException {};
@@ -93,6 +97,15 @@
      * Abstract base class for ports
      *
      * @param _name Port name including the owners name
+     * @param _owner Owner of the port
+     * @param _id A port identifier for vector ports
+     */
+    Port(const std::string& _name, SimObject* _owner, PortID _id);
+
+    /**
+     * Constructor for ports with no owner
+     *
+     * @param _name Port name including the owners name
      * @param _id A port identifier for vector ports
      */
     Port(const std::string& _name, PortID _id);
@@ -104,6 +117,12 @@
      */
     virtual ~Port();

+    /**
+     * Return a reference to this port's owner
+     */
+    SimObject& owner();
+    SimObject const& owner() const;
+
     /** Return a reference to this port's peer. */
     Port &getPeer() { return *_peer; }


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/67452?usp=email To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I29214278c3dd4829c89a6f7c93214b8123912e74
Gerrit-Change-Number: 67452
Gerrit-PatchSet: 1
Gerrit-Owner: Gabriel B. <gabriel.bus...@arteris.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org

Reply via email to