DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (777e60ca8853)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 ci et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/Mutex.h"
#include "mozilla/Scoped.h"

#include <algorithm>
#include <vector>

#include "PoisonIOInterposer.h"

// Auxiliary method to convert file descriptors to ids
#if defined(XP_WIN32)
#include <io.h>
inline intptr_t FileDescriptorToID(int aFd) {
  return _get_osfhandle(aFd);
}
#else
inline intptr_t FileDescriptorToID(int aFd) {
  return aFd;
}
#endif /* if not XP_WIN32 */

using namespace mozilla;

namespace {
struct DebugFilesAutoLockTraits {
  typedef PRLock *type;
  const static type empty() {
    return nullptr;
  }
  const static void release(type aL) {
    PR_Unlock(aL);
  }
};

class DebugFilesAutoLock : public Scoped<DebugFilesAutoLockTraits> {
  static PRLock *Lock;
public:
  static void Clear();
  static PRLock *getDebugFileIDsLock() {
    // On windows this static is not thread safe, but we know that the first
    // call is from
    // * An early registration of a debug FD or
    // * The call to InitWritePoisoning.
    // Since the early debug FDs are logs created early in the main thread
    // and no writes are trapped before InitWritePoisoning, we are safe.
    if (!Lock) {
      Lock = PR_NewLock();
    }

    // We have to use something lower level than a mutex. If we don't, we
    // can get recursive in here when called from logging a call to free.
    return Lock;
  }

  DebugFilesAutoLock() :
    Scoped<DebugFilesAutoLockTraits>(getDebugFileIDsLock()) {
    PR_Lock(get());
  }
};

PRLock *DebugFilesAutoLock::Lock;
void DebugFilesAutoLock::Clear() {
  MOZ_ASSERT(Lock != nullptr);
  Lock = nullptr;
}

// Return a vector used to hold the IDs of the current debug files. On unix
// an ID is a file descriptor. On Windows it is a file HANDLE.
std::vector<intptr_t>* getDebugFileIDs() {
  PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(DebugFilesAutoLock::getDebugFileIDsLock());
  // We have to use new as some write happen during static destructors
  // so an static std::vector might be destroyed while we still need it.
  static std::vector<intptr_t> *DebugFileIDs = new std::vector<intptr_t>();
  return DebugFileIDs;
}

} // anonymous namespace

namespace mozilla{

// Auxiliary Method to test if a file descriptor is registered to be ignored
// by the poisoning IO interposer
bool IsDebugFile(intptr_t aFileID) {
  DebugFilesAutoLock lockedScope;

  std::vector<intptr_t> &Vec = *getDebugFileIDs();
  return std::find(Vec.begin(), Vec.end(), aFileID) != Vec.end();
}

// Clean-up for the registered debug files.
// We should probably make sure all debug files are unregistered instead.
// But as the poison IO interposer is used for late-write checks we're not
// disabling it at any point yet. So Really no need for this.
//
// void ClearDebugFileRegister() {
//   PRLock *Lock;
//   {
//     DebugFilesAutoLock lockedScope;
//     delete getDebugFileIDs();
//     Lock = DebugFilesAutoLock::getDebugFileIDsLock();
//     DebugFilesAutoLock::Clear();
//   }
//   PR_DestroyLock(Lock);
// }

} // namespace mozilla

extern "C" {

  void MozillaRegisterDebugFD(int fd) {
    intptr_t fileId = FileDescriptorToID(fd);
    DebugFilesAutoLock lockedScope;
    std::vector<intptr_t> &Vec = *getDebugFileIDs();
    MOZ_ASSERT(std::find(Vec.begin(), Vec.end(), fileId) == Vec.end());
    Vec.push_back(fileId);
  }

  void MozillaRegisterDebugFILE(FILE *f) {
    int fd = fileno(f);
    if (fd == 1 || fd == 2) {
      return;
    }
    MozillaRegisterDebugFD(fd);
  }

  void MozillaUnRegisterDebugFD(int fd) {
    DebugFilesAutoLock lockedScope;
    intptr_t fileId = FileDescriptorToID(fd);
    std::vector<intptr_t> &Vec = *getDebugFileIDs();
    std::vector<intptr_t>::iterator i =
      std::find(Vec.begin(), Vec.end(), fileId);
    MOZ_ASSERT(i != Vec.end());
    Vec.erase(i);
  }

  void MozillaUnRegisterDebugFILE(FILE *f) {
    int fd = fileno(f);
    if (fd == 1 || fd == 2) {
      return;
    }
    fflush(f);
    MozillaUnRegisterDebugFD(fd);
  }

}