1 /****************************************************************************
2 * Copyright (C) 2006-2008 by Jason Ansel *
3 * jansel@csail.mit.edu *
4 * *
5 * This file is part of the JALIB module of DMTCP (DMTCP:dmtcp/jalib). *
6 * *
7 * DMTCP:dmtcp/jalib is free software: you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * DMTCP:dmtcp/src is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with DMTCP:dmtcp/src. If not, see *
19 * <http://www.gnu.org/licenses/>. *
20 ****************************************************************************/
21
22 #include "jassert.h"
23 #include "jfilesystem.h"
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include "jconvert.h"
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <dlfcn.h>
31
32 #include <fstream>
33 #include <execinfo.h> /* For backtrace() */
34
35 // Needed for dmtcp::UniquePid::getTmpDir()
36 // Is there a cleaner way to get information from rest of DMTCP?
37 #include "../src/uniquepid.h"
38 #include "../src/util.h"
39 #include "../src/protectedfds.h"
40
41 #undef JASSERT_CONT_A
42 #undef JASSERT_CONT_B
43
44 // This macro is also defined in ../src/constants.h and should always be kept
45 // in sync with that.
46 #define LIBC_FILENAME "libc.so.6"
47
48 #ifndef DMTCP
49 # define DECORATE_FN(fn) ::fn
50 #else
51 # include "syscallwrappers.h"
52 # define DECORATE_FN(fn) ::_real_ ## fn
53 #endif
54
55 int jassert_quiet = 0;
56
57 #define DUP_STDERR_FD PROTECTED_STDERR_FD
58 #define DUP_LOG_FD PROTECTED_JASSERTLOG_FD
59
60 static int jwrite(int fd, const char *str)
61 {
62 return dmtcp::Util::writeAll(fd, str, strlen(str));
63 #if 0
64 ssize_t offs, rc;
65 ssize_t size = strlen(str);
66
67 for (offs = 0; offs < size;) {
68 rc = write (fd, str + offs, size - offs);
69 if (rc == -1 && errno != EINTR && errno != EAGAIN)
70 return rc;
71 else if (rc > 0)
72 offs += rc;
73 }
74 return size;
75 #endif
76 }
77
78 int jassert_internal::jassert_console_fd()
79 {
80 //make sure stream is open
81 jassert_safe_print ( "" );
82 return DUP_STDERR_FD;
83 }
84
85 jassert_internal::JAssert& jassert_internal::JAssert::Text ( const char* msg )
86 {
87 Print ( "Message: " );
88 Print ( msg );
89 Print ( "\n" );
90 return *this;
91 }
92
93 static pthread_mutex_t logLock = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
94
95 bool jassert_internal::lockLog()
96 {
97 int retVal = pthread_mutex_lock(&logLock);
98 if (retVal != 0) {
99 perror ( "jassert_internal::lockLog: Error acquiring mutex");
100 }
101 return retVal == 0;
102 }
103
104 void jassert_internal::unlockLog()
105 {
106 int retVal = pthread_mutex_unlock(&logLock);
107 if (retVal != 0) {
108 perror ( "jassert_internal::unlockLog: Error releasing mutex");
109 }
110 }
111
112 jassert_internal::JAssert::JAssert ( bool exitWhenDone )
113 : JASSERT_CONT_A ( *this )
114 , JASSERT_CONT_B ( *this )
115 , _exitWhenDone ( exitWhenDone )
116 {
117 _logLockAcquired = jassert_internal::lockLog();
118 }
119
120 jassert_internal::JAssert::~JAssert()
121 {
122 if ( _exitWhenDone ) {
123 Print ( jalib::Filesystem::GetProgramName() );
124 Print ( " (" );
125 Print ( getpid() );
126 Print ( "): Terminating...\n" );
127 #ifdef DEBUG
128 jbacktrace();
129 #endif
130 }
131
132 jassert_safe_print ( ss.str().c_str() );
133 if ( _logLockAcquired )
134 jassert_internal::unlockLog();
135
136 if ( _exitWhenDone ) {
137 _exit ( 1 );
138 }
139 }
140
141 const char* jassert_internal::jassert_basename ( const char* str )
142 {
143 for ( const char* c = str; c[0] != '\0' && c[1] !='\0' ; ++c ) {
144 if ( c[0]=='/' )
145 str=c+1;
146 }
147 return str;
148 }
149
150 static int _open_log_safe ( const char* filename, int protectedFd )
151 {
152 //open file
|
Event tainted_string_sink_content_lv_call: |
Passing tainted string "filename" to "_real_open", which depends on its content. [details] |
153 int tfd = _real_open ( filename, O_WRONLY | O_APPEND | O_CREAT /*| O_SYNC*/,
154 S_IRUSR | S_IWUSR );
155 if (tfd == -1) return -1;
156 //change fd to 827 (DUP_LOG_FD -- PFD(6))
157 int nfd = dup2 ( tfd, protectedFd );
158 close ( tfd );
159
160 return nfd;
161 }
162
163 static int _open_log_safe ( const jalib::string& s, int protectedFd )
164 {
165 return _open_log_safe ( s.c_str(), protectedFd );
166 }
167
168
169 static int theLogFileFd = -1;
170 static int errConsoleFd = -1;
171
172 static jalib::string& theLogFilePath() {static jalib::string s;return s;};
173
174 void jassert_internal::jassert_init ( const jalib::string& f )
175 {
176 #ifdef DEBUG
177 JASSERT_SET_LOGFILE(f);
178 #endif
179 jassert_safe_print("");
180 }
181
182 const jalib::string writeJbacktraceMsg() {
183 jalib::string msg = jalib::string("")
184 + "\n *** Stack trace is available ***\n" \
185 " Execute: utils/dmtcp_backtrace.py [found in DMTCP_ROOT]\n" \
186 " For usage: utils/dmtcp_backtrace.py --help\n" \
187 " Files saved: ";
188 msg += dmtcp::UniquePid::getTmpDir()
189 + "/backtrace." + jalib::XToString ( getpid() );
190 msg += "\n ";
191 msg += dmtcp::UniquePid::getTmpDir()
192 + "/proc-maps." + jalib::XToString ( getpid() );
193 msg += "\n";
194 return msg;
195 }
196
197 void writeBacktrace() {
198 void *buffer[BT_SIZE];
199 int nptrs = backtrace(buffer, BT_SIZE);
200 jalib::string backtrace = dmtcp::UniquePid::getTmpDir()
201 + "/backtrace." + jalib::XToString ( getpid() );
202 int fd = open(backtrace.c_str(), O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
203 if (fd != -1) {
204 backtrace_symbols_fd( buffer, nptrs, fd );
205 close(fd);
206 jalib::string lnk = dmtcp::UniquePid::getTmpDir() + "/backtrace";
207 unlink(lnk.c_str()); // just in case it had previously been created.
208 if (symlink(backtrace.c_str(), lnk.c_str()) == -1)
209 {} // Too late to issue a user warning here.
210 }
211 }
212
213 // DOES: cp /proc/self/maps $DMTCP_TMPDIR/proc-maps
214 // But it could be dangerous to spawn a process in fragile state of JASSERT.
215 void writeProcMaps() {
216 char *mapsBuf = (char*) JALLOC_HELPER_MALLOC(50000);
217 int rc, count, total;
218 int fd = open("/proc/self/maps", O_RDONLY);
219 if (fd == -1) return;
220 count = dmtcp::Util::readAll(fd, mapsBuf, sizeof(mapsBuf) - 1);
221 close(fd);
222 jalib::string procMaps = dmtcp::UniquePid::getTmpDir()
223 + "/proc-maps." + jalib::XToString ( getpid() );
224 fd = open(procMaps.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);
225 if (fd == -1) return;
226 count = dmtcp::Util::writeAll(fd, mapsBuf, count);
227 close(fd);
228 jalib::string lnk = dmtcp::UniquePid::getTmpDir() + "/proc-maps";
229 unlink(lnk.c_str()); // just in case it had previously been created.
230 if (symlink(procMaps.c_str(), lnk.c_str()) == -1)
231 {} // Too late to issue a user warning here.
232 JALLOC_HELPER_FREE(mapsBuf);
233 }
234
235 jassert_internal::JAssert& jassert_internal::JAssert::jbacktrace ()
236 {
237 writeBacktrace();
238 writeProcMaps();
239 // This goes to stdout. Could also print to DUP_LOG_FD
240 Print( writeJbacktraceMsg() );
241 return *this; // Needed as part of JASSERT macro
242 }
243
244 void jassert_internal::reset_on_fork ( )
245 {
246 pthread_mutex_t newLock = PTHREAD_MUTEX_INITIALIZER;
247 logLock = newLock;
248 }
249
250 void jassert_internal::set_log_file ( const jalib::string& path )
251 {
252 theLogFilePath() = path;
253 if ( theLogFileFd != -1 ) close ( theLogFileFd );
254 theLogFileFd = -1;
255 if ( path.length() > 0 )
256 {
257 theLogFileFd = _open_log_safe ( path, DUP_LOG_FD );
258 if ( theLogFileFd == -1 )
259 theLogFileFd = _open_log_safe ( path + "_2", DUP_LOG_FD );
260 if ( theLogFileFd == -1 )
261 theLogFileFd = _open_log_safe ( path + "_3", DUP_LOG_FD );
262 if ( theLogFileFd == -1 )
263 theLogFileFd = _open_log_safe ( path + "_4", DUP_LOG_FD );
264 if ( theLogFileFd == -1 )
265 theLogFileFd = _open_log_safe ( path + "_5", DUP_LOG_FD );
266 }
267 }
268
269 static int _initJassertOutputDevices()
270 {
271 pthread_mutex_t newLock = PTHREAD_MUTEX_INITIALIZER;
272 logLock = newLock;
273
|
Event tainted_string_return_content: |
"getenv" returns tainted string content. |
|
Event var_assign: |
Assigning: "errpath" = "getenv("JALIB_STDERR_PATH")", which taints "errpath". |
| Also see events: |
[tainted_string] |
274 const char* errpath = getenv ( "JALIB_STDERR_PATH" );
275
276 #ifdef DEBUG
|
At conditional (1): "errpath != NULL": Taking true branch.
|
|
At conditional (2): "theLogFileFd == -1": Taking true branch.
|
277 if ( errpath != NULL && theLogFileFd == -1 ) {
278 JASSERT_SET_LOGFILE ( jalib::XToString(getenv("DMTCP_TMPDIR"))
279 + "/jassertlog." + jalib::XToString ( getpid() ) );
280 }
281 #endif
282
|
At conditional (3): "errpath != NULL": Taking true branch.
|
283 if ( errpath != NULL )
284 errConsoleFd = _open_log_safe ( errpath, DUP_STDERR_FD );
285 else
286 errConsoleFd = dup2 ( fileno ( stderr ), DUP_STDERR_FD );
287
288 if( errConsoleFd == -1 ) {
289 jwrite ( fileno (stderr ), "dmtcp: cannot open output channel for error logging\n");
290 return false;
291 }
292 return true;
293 }
294
295 void jassert_internal::jassert_safe_print ( const char* str )
296 {
297 static bool useErrorConsole = _initJassertOutputDevices();
298
299 if ( useErrorConsole )
300 jwrite ( errConsoleFd, str );
301
302 if ( theLogFileFd != -1 ) {
303 int rv = jwrite ( theLogFileFd, str );
304
305 if ( rv < 0 ) {
306 if ( useErrorConsole ) {
307 jwrite ( errConsoleFd, "JASSERT: write failed, reopening log file.\n" );
308 }
309 JASSERT_SET_LOGFILE ( theLogFilePath() );
310 if ( theLogFileFd != -1 ) {
311 jwrite ( theLogFileFd, "JASSERT: write failed, reopened log file:\n");
312 jwrite ( theLogFileFd, str );
313 }
314 }
315 }
316 }