operator<<(std::ostream, global_ptr<T>) does not match spec

Issue #223 resolved
Dan Bonachea created an issue

From the spec for operator<<(std::ostream, global_ptr<T>): (emphasis added)

Inserts an implementation-defined character representation of ptr into the output stream os. > The textual representation of two objects of type global_ptr<T, Kind> is identical if and only if the two global pointers compare equal.

This is currently broken for global_ptr<char>, as demonstrated by the following program:

#include <upcxx/upcxx.hpp>
#include <iostream>

using namespace std;
using namespace upcxx;

int main() {
  upcxx::init();

  std::ostringstream oss1, oss2;
  global_ptr<int> gpi = new_<int>(42);
  global_ptr<char> gpc = new_array<char>(80);
  strcpy(gpc.local(), "hello world");

  cout << gpi << endl;
  cout << gpc << endl;
  oss1 << gpc;
  strcpy(gpc.local(), "uh, oh.");
  oss2 << gpc;
  if (!rank_me()) {
    if (oss1.str() != oss2.str()) {
      cout << "ERROR: '" << oss1.str() << "' != '" << oss2.str() << "'" << endl;
    }
  }
  upcxx::barrier();
  gpc = NULL;
  cout << gpc << endl;

  upcxx::barrier();
  if (!rank_me()) cout << "done." << endl;
  upcxx::finalize();
  return 0;
}

Example output with 2019.3.2 release:

gp: 0, 0x6ffd7fa03c0, dev=-1)
(gp: 1, 0x6ffd7fa03c0, dev=-1)
(gp: 0, hello world, dev=-1)
(gp: 1, hello world, dev=-1)
ERROR: '(gp: 0, hello world, dev=-1)' != '(gp: 0, uh, oh., dev=-1)'
(gp: 0, (gp: 0,
<crash>

The problem is the implementation of operator<<(std::ostream, global_ptr<T>) is assuming that naively stringifying the T* rawptr always generates a representation of the pointer value. This works when T=int, but when T=char the result is actually dereferencing the pointer and treating it as a C string. This breaks the output contract of the method, but more importantly actually leads to crashes when the char * rawptr is NULL or remote.

The likely fix is to reinterpret cast to a void * or similar before stringifying rawptr.

Comments (3)

  1. Dan Bonachea reporter

    Proposed fix in pull request #223

    Resulting test output now looks like:

    (gp: 0, 0x7fb61a1d33c0, dev=-1)
    (gp: 0, 0x7fb61a1d33e8, dev=-1)
    (gp: 1, 0x7fb61a1d33c0, dev=-1)
    (gp: 1, 0x7fb61a1d33e8, dev=-1)
    (gp: 0, 0, dev=-1)
    (gp: 0, 0, dev=-1)
    done.
    
  2. Log in to comment