message: Increfing tapes when keeping them around calls to python API functions.
  These calls can trigger GIL releases or python GC which can trigger
  a change to the set of live tapes and segmentation faults.
diff: @@ -528,6 +528,34 @@ tensorflow::gtl::CompactPointerSet<TFE_Py_Tape*>* GetTapeSet() {
  return tape_set;
  }
  +// A safe copy of the current tapeset. Does not get affected by other python
  +// threads changing the set of active tapes.
  +class SafeTapeSet {
  + public:
  + SafeTapeSet() : tape_set_(*GetTapeSet()) {
  + for (auto* tape : tape_set_) {
  + Py_INCREF(tape);
  + }
  + }
  +
  + ~SafeTapeSet() {
  + for (auto* tape : tape_set_) {
  + Py_DECREF(tape);
  + }
  + }
  +
  + tensorflow::gtl::CompactPointerSet<TFE_Py_Tape*>::const_iterator begin() {
  + return tape_set_.begin();
  + }
  +
  + tensorflow::gtl::CompactPointerSet<TFE_Py_Tape*>::const_iterator end() {
  + return tape_set_.end();
  + }
  +
  + private:
  + tensorflow::gtl::CompactPointerSet<TFE_Py_Tape*> tape_set_;
  +};
  +
  // xcode 7 doesn't define thread_local, so for compatibility we implement our
  // own. TODO(apassos) remove once we can deprecate xcode 7.
  #ifndef __APPLE__
  @@ -718,10 +746,7 @@ void TFE_Py_TapeSetWatchVariable(PyObject* variable) {
  if (*ThreadTapeIsStopped()) {
  return;
  }
  - // Note: making a copy because watching a variable can trigger a change to the
  - // set of tapes by allowing python's garbage collector to run.
  - auto tape_set = *GetTapeSet();
  - for (TFE_Py_Tape* tape : tape_set) {
  + for (TFE_Py_Tape* tape : SafeTapeSet()) {
  tape->tape->WatchVariable(variable);
  }
  }
  @@ -777,8 +802,7 @@ void TFE_Py_TapeSetRecordOperation(PyObject* op_type, PyObject* output_tensors,
  return;
  }
  - auto set = *GetTapeSet();
  - for (TFE_Py_Tape* tape : set) {
  + for (TFE_Py_Tape* tape : SafeTapeSet()) {
  Py_INCREF(backward_function);
  tape->tape->RecordOperation(
  op_type_str, output_info, input_ids, backward_function,
  @@ -787,10 +811,7 @@ void TFE_Py_TapeSetRecordOperation(PyObject* op_type, PyObject* output_tensors,
  }
  void TFE_Py_TapeSetDeleteTrace(tensorflow::int64 tensor_id) {
  - // Note: making a copy because deleting the trace can trigger a change to the
  - // set of tapes by allowing python's garbage collector to run.
  - auto tape_set = *GetTapeSet();
  - for (TFE_Py_Tape* tape : tape_set) {
  + for (TFE_Py_Tape* tape : SafeTapeSet()) {
  tape->tape->DeleteTrace(tensor_id);
  }
  }
  