Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/build/NSPRInterposer.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "IOInterposer.h"
8
#include "NSPRInterposer.h"
9
10
#include "prio.h"
11
#include "private/pprio.h"
12
#include "nsDebug.h"
13
#include "nscore.h"
14
15
namespace {
16
17
using namespace mozilla;
18
19
/* Original IO methods */
20
PRCloseFN sCloseFn = nullptr;
21
PRReadFN  sReadFn  = nullptr;
22
PRWriteFN sWriteFn = nullptr;
23
PRFsyncFN sFSyncFn = nullptr;
24
PRFileInfoFN sFileInfoFn = nullptr;
25
PRFileInfo64FN sFileInfo64Fn = nullptr;
26
27
/**
28
 * RAII class for timing the duration of an NSPR I/O call and reporting the
29
 * result to the IOInterposeObserver API.
30
 */
31
class NSPRIOAutoObservation : public IOInterposeObserver::Observation
32
{
33
public:
34
  explicit NSPRIOAutoObservation(IOInterposeObserver::Operation aOp)
35
    : IOInterposeObserver::Observation(aOp, "NSPRIOInterposer")
36
54
  {
37
54
  }
38
39
  ~NSPRIOAutoObservation() override
40
54
  {
41
54
    Report();
42
54
  }
43
};
44
45
PRStatus PR_CALLBACK
46
interposedClose(PRFileDesc* aFd)
47
18
{
48
18
  // If we don't have a valid original function pointer something is very wrong.
49
18
  NS_ASSERTION(sCloseFn, "NSPR IO Interposing: sCloseFn is NULL");
50
18
51
18
  NSPRIOAutoObservation timer(IOInterposeObserver::OpClose);
52
18
  return sCloseFn(aFd);
53
18
}
54
55
int32_t PR_CALLBACK
56
interposedRead(PRFileDesc* aFd, void* aBuf, int32_t aAmt)
57
27
{
58
27
  // If we don't have a valid original function pointer something is very wrong.
59
27
  NS_ASSERTION(sReadFn, "NSPR IO Interposing: sReadFn is NULL");
60
27
61
27
  NSPRIOAutoObservation timer(IOInterposeObserver::OpRead);
62
27
  return sReadFn(aFd, aBuf, aAmt);
63
27
}
64
65
int32_t PR_CALLBACK
66
interposedWrite(PRFileDesc* aFd, const void* aBuf, int32_t aAmt)
67
0
{
68
0
  // If we don't have a valid original function pointer something is very wrong.
69
0
  NS_ASSERTION(sWriteFn, "NSPR IO Interposing: sWriteFn is NULL");
70
0
71
0
  NSPRIOAutoObservation timer(IOInterposeObserver::OpWrite);
72
0
  return sWriteFn(aFd, aBuf, aAmt);
73
0
}
74
75
PRStatus PR_CALLBACK
76
interposedFSync(PRFileDesc* aFd)
77
0
{
78
0
  // If we don't have a valid original function pointer something is very wrong.
79
0
  NS_ASSERTION(sFSyncFn, "NSPR IO Interposing: sFSyncFn is NULL");
80
0
81
0
  NSPRIOAutoObservation timer(IOInterposeObserver::OpFSync);
82
0
  return sFSyncFn(aFd);
83
0
}
84
85
PRStatus PR_CALLBACK
86
interposedFileInfo(PRFileDesc* aFd, PRFileInfo* aInfo)
87
3
{
88
3
  // If we don't have a valid original function pointer something is very wrong.
89
3
  NS_ASSERTION(sFileInfoFn, "NSPR IO Interposing: sFileInfoFn is NULL");
90
3
91
3
  NSPRIOAutoObservation timer(IOInterposeObserver::OpStat);
92
3
  return sFileInfoFn(aFd, aInfo);
93
3
}
94
95
PRStatus PR_CALLBACK
96
interposedFileInfo64(PRFileDesc* aFd, PRFileInfo64* aInfo)
97
6
{
98
6
  // If we don't have a valid original function pointer something is very wrong.
99
6
  NS_ASSERTION(sFileInfo64Fn, "NSPR IO Interposing: sFileInfo64Fn is NULL");
100
6
101
6
  NSPRIOAutoObservation timer(IOInterposeObserver::OpStat);
102
6
  return sFileInfo64Fn(aFd, aInfo);
103
6
}
104
105
} // namespace
106
107
namespace mozilla {
108
109
void
110
InitNSPRIOInterposing()
111
3
{
112
3
  // Check that we have not interposed any of the IO methods before
113
3
  MOZ_ASSERT(!sCloseFn && !sReadFn && !sWriteFn && !sFSyncFn && !sFileInfoFn &&
114
3
             !sFileInfo64Fn);
115
3
116
3
  // We can't actually use this assertion because we initialize this code
117
3
  // before XPCOM is initialized, so NS_IsMainThread() always returns false.
118
3
  // MOZ_ASSERT(NS_IsMainThread());
119
3
120
3
  // Get IO methods from NSPR and const cast the structure so we can modify it.
121
3
  PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods());
122
3
123
3
  // Something is badly wrong if we don't get IO methods... However, we don't
124
3
  // want to crash over that in non-debug builds. This is unlikely to happen
125
3
  // so an assert is enough, no need to report it to the caller.
126
3
  MOZ_ASSERT(methods);
127
3
  if (!methods) {
128
0
    return;
129
0
  }
130
3
131
3
  // Store original functions
132
3
  sCloseFn      = methods->close;
133
3
  sReadFn       = methods->read;
134
3
  sWriteFn      = methods->write;
135
3
  sFSyncFn      = methods->fsync;
136
3
  sFileInfoFn   = methods->fileInfo;
137
3
  sFileInfo64Fn = methods->fileInfo64;
138
3
139
3
  // Overwrite with our interposed functions
140
3
  methods->close      = &interposedClose;
141
3
  methods->read       = &interposedRead;
142
3
  methods->write      = &interposedWrite;
143
3
  methods->fsync      = &interposedFSync;
144
3
  methods->fileInfo   = &interposedFileInfo;
145
3
  methods->fileInfo64 = &interposedFileInfo64;
146
3
}
147
148
void
149
ClearNSPRIOInterposing()
150
0
{
151
0
  // If we have already cleared IO interposing, or not initialized it this is
152
0
  // actually bad.
153
0
  MOZ_ASSERT(sCloseFn && sReadFn && sWriteFn && sFSyncFn && sFileInfoFn &&
154
0
             sFileInfo64Fn);
155
0
156
0
  // Get IO methods from NSPR and const cast the structure so we can modify it.
157
0
  PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods());
158
0
159
0
  // Something is badly wrong if we don't get IO methods... However, we don't
160
0
  // want to crash over that in non-debug builds. This is unlikely to happen
161
0
  // so an assert is enough, no need to report it to the caller.
162
0
  MOZ_ASSERT(methods);
163
0
  if (!methods) {
164
0
    return;
165
0
  }
166
0
167
0
  // Restore original functions
168
0
  methods->close      = sCloseFn;
169
0
  methods->read       = sReadFn;
170
0
  methods->write      = sWriteFn;
171
0
  methods->fsync      = sFSyncFn;
172
0
  methods->fileInfo   = sFileInfoFn;
173
0
  methods->fileInfo64 = sFileInfo64Fn;
174
0
175
0
  // Forget about original functions
176
0
  sCloseFn      = nullptr;
177
0
  sReadFn       = nullptr;
178
0
  sWriteFn      = nullptr;
179
0
  sFSyncFn      = nullptr;
180
0
  sFileInfoFn   = nullptr;
181
0
  sFileInfo64Fn = nullptr;
182
0
}
183
184
} // namespace mozilla
185