Bug report: Config::Set may fail to set the attribute by using Names::Add

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Bug report: Config::Set may fail to set the attribute by using Names::Add

Dizhi Zhou-2
*/*Description*/*
Consider the following example script:
   // create a node
  NodeContainer nodes;
  nodes.Create (1);

   // install a P2P netdevice to the node
  PointToPointHelper pointToPoint;
  NetDeviceContainer devices;
  devices = pointToPoint.Install (nodes);

  // Add internet stack
  InternetStackHelper stack;
  stack.Install (nodes);

  // Define alias strings to represent the node and the netdevice
  Names::Add ("client", nodes.Get (0));
  Names::Add ("client/device", nodes.Get (0)->GetDevice (0));

  // Set DataRate attribute using such alias strings
  Config::Set ("/Names/client/device/$ns3::PointToPointNetDevice/DataRate",
StringValue ("2.5Mbps"));

The Config::Set doesn't work. The DataRate attribute is still equal to its
original default value (i,e, 32768bps).

However, the Config::Set works when we InternetStackHelper::Install() is
called after Names::Add and Config::Set.

*/* Root cause analysis */*
In Config::Set call stack, it calls Names::Find () to get the object
pointer of a string.
Resolver::DoResolve ()
{
  ...
  Ptr<Object> namedObject = *Names::Find<Object>* (root, item);
  ...
}

I print the namedObject name and item in both two cases
// Case 1: use InternetStackHelper::Install() *after* Config::Set and
Names::Add
item == client,  but namedObject == Node // expected results

// Case 2: use InternetStackHelper::Install() *before* Config::Set and
Names::Add
item == client,  but namedObject == Ipv4L3Protocol

In Case 2, Config::Set fails since it's unable find PointToPointNetDevice
from Ipv4L3Protocol.

Why Names::Find returns Ipv4L3Protocol instead of Node?
template <typename T>
/* static */
Ptr<T>
Names::Find (Ptr<Object> context, std::string name)
{
  Ptr<Object> obj = FindInternal (context, name);
  if (obj)
    {
      return *obj->GetObject<T> ();*
    }
...
}

In our example, T== Object, name == "client", obj == Node. . However,
obj->GetObject<T> returns object Ipv4L3Protocol, instead of object Node!!

Why?
template <typename T>
Ptr<T>
Object::GetObject () const
{
  // This is an optimization: if the cast works (which is likely),
  // things will be pretty fast.
  T *result = dynamic_cast<T *> (m_aggregates->buffer[0]);
  if (result != 0)
    {
      return Ptr<T> (result);
    }
  // if the cast does not work, we try to do a full type check.
  Ptr<Object> found = DoGetObject (T::GetTypeId ());
  if (found != 0)
    {
      return Ptr<T> (static_cast<T *> (PeekPointer (found)));
    }
  return 0;
}

GetObject() always do a dynamic_cast on the first object in the aggregate
list. In our case, Since T == Object in Case 2, such dynamic_cast always
successes. Therefore, Names::Find<Object>(root, item) can only return the
first object in the root's aggregation list.

In my example, before using InternetStackHelper::Instal(), the only object
in the Node aggregation list is the Node itself. After calling this
function, however, Ipv4L3Protocol becomes the first object in that list,
which causes the Config::Set failure.


*/*Solution*/*
For all Names::Find functions, use GetObject (TypeId), instead of
GetObject()

Names::Find (Ptr<Object> context, std::string name)
{
  Ptr<Object> obj = FindInternal (context, name);
  if (obj)
    {
      return *obj->GetObject<**obj->GetInstanceTypeId ()> ();*
    }
...
}

GetObject (TypeId) function will find the specified object from the
aggregate object list.

template <typename T>
Ptr<T>
Object::GetObject (TypeId tid) const
{
  Ptr<Object> found = DoGetObject (tid);
  if (found != 0)
    {
      return Ptr<T> (static_cast<T *> (PeekPointer (found)));
    }
  return 0;
}

I only test this solution in such example script. I may do a fully test and
add some test examples in this summer during my spare time.


Regards,
Dizhi
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Bug report: Config::Set may fail to set the attribute by using Names::Add

Manoj Rana
Hi,
Better not to send the code, you could introduce the problem first i.e.
what you understand about the problem. It would be more meaningful for the
developers.
Regards,
manoj

On Thu, Jun 15, 2017 at 8:03 PM, Dizhi Zhou <[hidden email]> wrote:

> */*Description*/*
> Consider the following example script:
>    // create a node
>   NodeContainer nodes;
>   nodes.Create (1);
>
>    // install a P2P netdevice to the node
>   PointToPointHelper pointToPoint;
>   NetDeviceContainer devices;
>   devices = pointToPoint.Install (nodes);
>
>   // Add internet stack
>   InternetStackHelper stack;
>   stack.Install (nodes);
>
>   // Define alias strings to represent the node and the netdevice
>   Names::Add ("client", nodes.Get (0));
>   Names::Add ("client/device", nodes.Get (0)->GetDevice (0));
>
>   // Set DataRate attribute using such alias strings
>   Config::Set ("/Names/client/device/$ns3::PointToPointNetDevice/
> DataRate",
> StringValue ("2.5Mbps"));
>
> The Config::Set doesn't work. The DataRate attribute is still equal to its
> original default value (i,e, 32768bps).
>
> However, the Config::Set works when we InternetStackHelper::Install() is
> called after Names::Add and Config::Set.
>
> */* Root cause analysis */*
> In Config::Set call stack, it calls Names::Find () to get the object
> pointer of a string.
> Resolver::DoResolve ()
> {
>   ...
>   Ptr<Object> namedObject = *Names::Find<Object>* (root, item);
>   ...
> }
>
> I print the namedObject name and item in both two cases
> // Case 1: use InternetStackHelper::Install() *after* Config::Set and
> Names::Add
> item == client,  but namedObject == Node // expected results
>
> // Case 2: use InternetStackHelper::Install() *before* Config::Set and
> Names::Add
> item == client,  but namedObject == Ipv4L3Protocol
>
> In Case 2, Config::Set fails since it's unable find PointToPointNetDevice
> from Ipv4L3Protocol.
>
> Why Names::Find returns Ipv4L3Protocol instead of Node?
> template <typename T>
> /* static */
> Ptr<T>
> Names::Find (Ptr<Object> context, std::string name)
> {
>   Ptr<Object> obj = FindInternal (context, name);
>   if (obj)
>     {
>       return *obj->GetObject<T> ();*
>     }
> ...
> }
>
> In our example, T== Object, name == "client", obj == Node. . However,
> obj->GetObject<T> returns object Ipv4L3Protocol, instead of object Node!!
>
> Why?
> template <typename T>
> Ptr<T>
> Object::GetObject () const
> {
>   // This is an optimization: if the cast works (which is likely),
>   // things will be pretty fast.
>   T *result = dynamic_cast<T *> (m_aggregates->buffer[0]);
>   if (result != 0)
>     {
>       return Ptr<T> (result);
>     }
>   // if the cast does not work, we try to do a full type check.
>   Ptr<Object> found = DoGetObject (T::GetTypeId ());
>   if (found != 0)
>     {
>       return Ptr<T> (static_cast<T *> (PeekPointer (found)));
>     }
>   return 0;
> }
>
> GetObject() always do a dynamic_cast on the first object in the aggregate
> list. In our case, Since T == Object in Case 2, such dynamic_cast always
> successes. Therefore, Names::Find<Object>(root, item) can only return the
> first object in the root's aggregation list.
>
> In my example, before using InternetStackHelper::Instal(), the only object
> in the Node aggregation list is the Node itself. After calling this
> function, however, Ipv4L3Protocol becomes the first object in that list,
> which causes the Config::Set failure.
>
>
> */*Solution*/*
> For all Names::Find functions, use GetObject (TypeId), instead of
> GetObject()
>
> Names::Find (Ptr<Object> context, std::string name)
> {
>   Ptr<Object> obj = FindInternal (context, name);
>   if (obj)
>     {
>       return *obj->GetObject<**obj->GetInstanceTypeId ()> ();*
>     }
> ...
> }
>
> GetObject (TypeId) function will find the specified object from the
> aggregate object list.
>
> template <typename T>
> Ptr<T>
> Object::GetObject (TypeId tid) const
> {
>   Ptr<Object> found = DoGetObject (tid);
>   if (found != 0)
>     {
>       return Ptr<T> (static_cast<T *> (PeekPointer (found)));
>     }
>   return 0;
> }
>
> I only test this solution in such example script. I may do a fully test and
> add some test examples in this summer during my spare time.
>
>
> Regards,
> Dizhi
>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Bug report: Config::Set may fail to set the attribute by using Names::Add

Dizhi Zhou-2
Hi Manoj,

In brief, the problem I see is that Config::Set function may fail to set an
attribute if 1) its name-space path uses a string defined by Names::Add and
2) Config::Set is called after any object aggregation (e.g.,
InternetStackHelper::Install() function).

How to reproduce this problem can be found  in the "/*Description*/"
section of my first Email (
http://mailman.isi.edu/pipermail/ns-developers/2017-June/013967.html).

My first Email explained the root cause of this bug and proposed a solution
as well.

Please let me know if you have any other questions.

Regards,
Dizhi
‚Äč
Loading...