Line data Source code
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 1695 : explicit NSPRIOAutoObservation(IOInterposeObserver::Operation aOp)
35 1695 : : IOInterposeObserver::Observation(aOp, "NSPRIOInterposer")
36 : {
37 1695 : }
38 :
39 1695 : ~NSPRIOAutoObservation() override
40 3390 : {
41 1695 : Report();
42 1695 : }
43 : };
44 :
45 : PRStatus PR_CALLBACK
46 599 : interposedClose(PRFileDesc* aFd)
47 : {
48 : // If we don't have a valid original function pointer something is very wrong.
49 599 : NS_ASSERTION(sCloseFn, "NSPR IO Interposing: sCloseFn is NULL");
50 :
51 1198 : NSPRIOAutoObservation timer(IOInterposeObserver::OpClose);
52 1198 : return sCloseFn(aFd);
53 : }
54 :
55 : int32_t PR_CALLBACK
56 628 : interposedRead(PRFileDesc* aFd, void* aBuf, int32_t aAmt)
57 : {
58 : // If we don't have a valid original function pointer something is very wrong.
59 628 : NS_ASSERTION(sReadFn, "NSPR IO Interposing: sReadFn is NULL");
60 :
61 1256 : NSPRIOAutoObservation timer(IOInterposeObserver::OpRead);
62 1256 : return sReadFn(aFd, aBuf, aAmt);
63 : }
64 :
65 : int32_t PR_CALLBACK
66 116 : interposedWrite(PRFileDesc* aFd, const void* aBuf, int32_t aAmt)
67 : {
68 : // If we don't have a valid original function pointer something is very wrong.
69 116 : NS_ASSERTION(sWriteFn, "NSPR IO Interposing: sWriteFn is NULL");
70 :
71 232 : NSPRIOAutoObservation timer(IOInterposeObserver::OpWrite);
72 232 : return sWriteFn(aFd, aBuf, aAmt);
73 : }
74 :
75 : PRStatus PR_CALLBACK
76 6 : interposedFSync(PRFileDesc* aFd)
77 : {
78 : // If we don't have a valid original function pointer something is very wrong.
79 6 : NS_ASSERTION(sFSyncFn, "NSPR IO Interposing: sFSyncFn is NULL");
80 :
81 12 : NSPRIOAutoObservation timer(IOInterposeObserver::OpFSync);
82 12 : return sFSyncFn(aFd);
83 : }
84 :
85 : PRStatus PR_CALLBACK
86 1 : interposedFileInfo(PRFileDesc* aFd, PRFileInfo* aInfo)
87 : {
88 : // If we don't have a valid original function pointer something is very wrong.
89 1 : NS_ASSERTION(sFileInfoFn, "NSPR IO Interposing: sFileInfoFn is NULL");
90 :
91 2 : NSPRIOAutoObservation timer(IOInterposeObserver::OpStat);
92 2 : return sFileInfoFn(aFd, aInfo);
93 : }
94 :
95 : PRStatus PR_CALLBACK
96 345 : interposedFileInfo64(PRFileDesc* aFd, PRFileInfo64* aInfo)
97 : {
98 : // If we don't have a valid original function pointer something is very wrong.
99 345 : NS_ASSERTION(sFileInfo64Fn, "NSPR IO Interposing: sFileInfo64Fn is NULL");
100 :
101 690 : NSPRIOAutoObservation timer(IOInterposeObserver::OpStat);
102 690 : return sFileInfo64Fn(aFd, aInfo);
103 : }
104 :
105 : } // namespace
106 :
107 : namespace mozilla {
108 :
109 : void
110 1 : InitNSPRIOInterposing()
111 : {
112 : // Check that we have not interposed any of the IO methods before
113 1 : MOZ_ASSERT(!sCloseFn && !sReadFn && !sWriteFn && !sFSyncFn && !sFileInfoFn &&
114 : !sFileInfo64Fn);
115 :
116 : // We can't actually use this assertion because we initialize this code
117 : // before XPCOM is initialized, so NS_IsMainThread() always returns false.
118 : // MOZ_ASSERT(NS_IsMainThread());
119 :
120 : // Get IO methods from NSPR and const cast the structure so we can modify it.
121 1 : PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods());
122 :
123 : // Something is badly wrong if we don't get IO methods... However, we don't
124 : // want to crash over that in non-debug builds. This is unlikely to happen
125 : // so an assert is enough, no need to report it to the caller.
126 1 : MOZ_ASSERT(methods);
127 1 : if (!methods) {
128 0 : return;
129 : }
130 :
131 : // Store original functions
132 1 : sCloseFn = methods->close;
133 1 : sReadFn = methods->read;
134 1 : sWriteFn = methods->write;
135 1 : sFSyncFn = methods->fsync;
136 1 : sFileInfoFn = methods->fileInfo;
137 1 : sFileInfo64Fn = methods->fileInfo64;
138 :
139 : // Overwrite with our interposed functions
140 1 : methods->close = &interposedClose;
141 1 : methods->read = &interposedRead;
142 1 : methods->write = &interposedWrite;
143 1 : methods->fsync = &interposedFSync;
144 1 : methods->fileInfo = &interposedFileInfo;
145 1 : methods->fileInfo64 = &interposedFileInfo64;
146 : }
147 :
148 : void
149 0 : ClearNSPRIOInterposing()
150 : {
151 : // If we have already cleared IO interposing, or not initialized it this is
152 : // actually bad.
153 0 : MOZ_ASSERT(sCloseFn && sReadFn && sWriteFn && sFSyncFn && sFileInfoFn &&
154 : sFileInfo64Fn);
155 :
156 : // 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 :
159 : // Something is badly wrong if we don't get IO methods... However, we don't
160 : // want to crash over that in non-debug builds. This is unlikely to happen
161 : // 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 : }
166 :
167 : // 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 :
175 : // 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 : }
183 :
184 : } // namespace mozilla
185 :
|