Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / xpcom / base / nsDebugImpl.cpp
bloba4a7ec2e2b9cc0ea5d3d627e00e6e8fd011f59f8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * IBM Corp.
24 * Henry Sobotka
25 * Benjamin Smedberg <benjamin@smedbergs.us>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsDebugImpl.h"
42 #include "nsDebug.h"
43 #include "prprf.h"
44 #include "prlog.h"
45 #include "prinit.h"
46 #include "plstr.h"
47 #include "nsError.h"
48 #include "prerror.h"
49 #include "prerr.h"
50 #include "prenv.h"
52 #if defined(XP_BEOS)
53 /* For DEBUGGER macros */
54 #include <Debug.h>
55 #endif
57 #if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS)
58 /* for abort() and getenv() */
59 #include <stdlib.h>
60 #endif
62 #include "nsTraceRefcntImpl.h"
63 #include "nsISupportsUtils.h"
65 #if defined(XP_UNIX)
66 #include <signal.h>
67 #endif
69 #if defined(XP_WIN)
70 #include <tchar.h>
71 #include "nsString.h"
72 #endif
74 static void
75 Abort(const char *aMsg);
77 static void
78 Break(const char *aMsg);
80 #if defined(XP_OS2)
81 # define INCL_WINDIALOGS // need for WinMessageBox
82 # include <os2.h>
83 # include <string.h>
84 #endif /* XP_OS2 */
86 #if defined(_WIN32)
87 #include <windows.h>
88 #include <signal.h>
89 #include <malloc.h> // for _alloca
90 #elif defined(XP_UNIX)
91 #include <stdlib.h>
92 #endif
94 NS_IMPL_QUERY_INTERFACE1(nsDebugImpl, nsIDebug)
96 NS_IMETHODIMP_(nsrefcnt)
97 nsDebugImpl::AddRef()
99 return 2;
102 NS_IMETHODIMP_(nsrefcnt)
103 nsDebugImpl::Release()
105 return 1;
108 NS_IMETHODIMP
109 nsDebugImpl::Assertion(const char *aStr, const char *aExpr,
110 const char *aFile, PRInt32 aLine)
112 NS_DebugBreak(NS_DEBUG_ASSERTION, aStr, aExpr, aFile, aLine);
113 return NS_OK;
116 NS_IMETHODIMP
117 nsDebugImpl::Warning(const char *aStr, const char *aFile, PRInt32 aLine)
119 NS_DebugBreak(NS_DEBUG_WARNING, aStr, nsnull, aFile, aLine);
120 return NS_OK;
123 NS_IMETHODIMP
124 nsDebugImpl::Break(const char *aFile, PRInt32 aLine)
126 NS_DebugBreak(NS_DEBUG_BREAK, nsnull, nsnull, aFile, aLine);
127 return NS_OK;
130 NS_IMETHODIMP
131 nsDebugImpl::Abort(const char *aFile, PRInt32 aLine)
133 NS_DebugBreak(NS_DEBUG_ABORT, nsnull, nsnull, aFile, aLine);
134 return NS_OK;
138 * Implementation of the nsDebug methods. Note that this code is
139 * always compiled in, in case some other module that uses it is
140 * compiled with debugging even if this library is not.
142 static PRLogModuleInfo* gDebugLog;
144 static void InitLog(void)
146 if (0 == gDebugLog) {
147 gDebugLog = PR_NewLogModule("nsDebug");
148 gDebugLog->level = PR_LOG_DEBUG;
152 enum nsAssertBehavior {
153 NS_ASSERT_UNINITIALIZED,
154 NS_ASSERT_WARN,
155 NS_ASSERT_SUSPEND,
156 NS_ASSERT_STACK,
157 NS_ASSERT_TRAP,
158 NS_ASSERT_ABORT,
159 NS_ASSERT_STACK_AND_ABORT
162 static nsAssertBehavior GetAssertBehavior()
164 static nsAssertBehavior gAssertBehavior = NS_ASSERT_UNINITIALIZED;
165 if (gAssertBehavior != NS_ASSERT_UNINITIALIZED)
166 return gAssertBehavior;
168 #if defined(XP_WIN) || defined(XP_OS2)
169 gAssertBehavior = NS_ASSERT_TRAP;
170 #else
171 gAssertBehavior = NS_ASSERT_WARN;
172 #endif
174 const char *assertString = PR_GetEnv("XPCOM_DEBUG_BREAK");
175 if (!assertString || !*assertString)
176 return gAssertBehavior;
178 if (!strcmp(assertString, "warn"))
179 return gAssertBehavior = NS_ASSERT_WARN;
181 if (!strcmp(assertString, "suspend"))
182 return gAssertBehavior = NS_ASSERT_SUSPEND;
184 if (!strcmp(assertString, "stack"))
185 return gAssertBehavior = NS_ASSERT_STACK;
187 if (!strcmp(assertString, "abort"))
188 return gAssertBehavior = NS_ASSERT_ABORT;
190 if (!strcmp(assertString, "trap") || !strcmp(assertString, "break"))
191 return gAssertBehavior = NS_ASSERT_TRAP;
193 if (!strcmp(assertString, "stack-and-abort"))
194 return gAssertBehavior = NS_ASSERT_STACK_AND_ABORT;
196 fprintf(stderr, "Unrecognized value of XPCOM_DEBUG_BREAK\n");
197 return gAssertBehavior;
200 struct FixedBuffer
202 FixedBuffer() : curlen(0) { buffer[0] = '\0'; }
204 char buffer[1000];
205 PRUint32 curlen;
208 static PRIntn
209 StuffFixedBuffer(void *closure, const char *buf, PRUint32 len)
211 if (!len)
212 return 0;
214 FixedBuffer *fb = (FixedBuffer*) closure;
216 // strip the trailing null, we add it again later
217 if (buf[len - 1] == '\0')
218 --len;
220 if (fb->curlen + len >= sizeof(fb->buffer))
221 len = sizeof(fb->buffer) - fb->curlen - 1;
223 if (len) {
224 memcpy(fb->buffer + fb->curlen, buf, len);
225 fb->curlen += len;
226 fb->buffer[fb->curlen] = '\0';
229 return len;
232 EXPORT_XPCOM_API(void)
233 NS_DebugBreak(PRUint32 aSeverity, const char *aStr, const char *aExpr,
234 const char *aFile, PRInt32 aLine)
236 InitLog();
238 FixedBuffer buf;
239 PRLogModuleLevel ll = PR_LOG_WARNING;
240 const char *sevString = "WARNING";
242 switch (aSeverity) {
243 case NS_DEBUG_ASSERTION:
244 sevString = "###!!! ASSERTION";
245 ll = PR_LOG_ERROR;
246 break;
248 case NS_DEBUG_BREAK:
249 sevString = "###!!! BREAK";
250 ll = PR_LOG_ALWAYS;
251 break;
253 case NS_DEBUG_ABORT:
254 sevString = "###!!! ABORT";
255 ll = PR_LOG_ALWAYS;
256 break;
258 default:
259 aSeverity = NS_DEBUG_WARNING;
262 PR_sxprintf(StuffFixedBuffer, &buf, "%s: ", sevString);
264 if (aStr)
265 PR_sxprintf(StuffFixedBuffer, &buf, "%s: ", aStr);
267 if (aExpr)
268 PR_sxprintf(StuffFixedBuffer, &buf, "'%s', ", aExpr);
270 if (aFile)
271 PR_sxprintf(StuffFixedBuffer, &buf, "file %s, ", aFile);
273 if (aLine != -1)
274 PR_sxprintf(StuffFixedBuffer, &buf, "line %d", aLine);
276 // Write out the message to the debug log
277 PR_LOG(gDebugLog, ll, ("%s", buf.buffer));
278 PR_LogFlush();
280 // errors on platforms without a debugdlg ring a bell on stderr
281 #if !defined(XP_WIN) && !defined(XP_OS2)
282 if (ll != PR_LOG_WARNING)
283 fprintf(stderr, "\07");
284 #endif
286 // Write the message to stderr
287 fprintf(stderr, "%s\n", buf.buffer);
288 fflush(stderr);
290 switch (aSeverity) {
291 case NS_DEBUG_WARNING:
292 return;
294 case NS_DEBUG_BREAK:
295 Break(buf.buffer);
296 return;
298 case NS_DEBUG_ABORT:
299 nsTraceRefcntImpl::WalkTheStack(stderr);
300 Abort(buf.buffer);
301 return;
304 // Now we deal with assertions
306 switch (GetAssertBehavior()) {
307 case NS_ASSERT_WARN:
308 return;
310 case NS_ASSERT_SUSPEND:
311 #ifdef XP_UNIX
312 fprintf(stderr, "Suspending process; attach with the debugger.\n");
313 kill(0, SIGSTOP);
314 #else
315 Break(buf.buffer);
316 #endif
317 return;
319 case NS_ASSERT_STACK:
320 nsTraceRefcntImpl::WalkTheStack(stderr);
321 return;
323 case NS_ASSERT_STACK_AND_ABORT:
324 nsTraceRefcntImpl::WalkTheStack(stderr);
325 // Fall through to abort
327 case NS_ASSERT_ABORT:
328 Abort(buf.buffer);
329 return;
331 case NS_ASSERT_TRAP:
332 Break(buf.buffer);
336 static void
337 Abort(const char *aMsg)
339 #if defined(_WIN32)
341 #ifndef WINCE
342 //This should exit us
343 raise(SIGABRT);
344 #endif
345 //If we are ignored exit this way..
346 _exit(3);
347 #elif defined(XP_UNIX)
348 PR_Abort();
349 #elif defined(XP_BEOS)
351 #ifndef DEBUG_cls
352 DEBUGGER(aMsg);
353 #endif
355 #else
356 // Don't know how to abort on this platform! call Break() instead
357 Break(aMsg);
358 #endif
361 // Abort() calls this function, don't call it!
362 static void
363 Break(const char *aMsg)
365 #if defined(_WIN32)
366 #ifndef WINCE // we really just want to crash for now
367 static int ignoreDebugger;
368 if (!ignoreDebugger) {
369 const char *shouldIgnoreDebugger = getenv("XPCOM_DEBUG_DLG");
370 ignoreDebugger = 1 + (shouldIgnoreDebugger && !strcmp(shouldIgnoreDebugger, "1"));
372 if ((ignoreDebugger == 2) || !::IsDebuggerPresent()) {
373 DWORD code = IDRETRY;
375 /* Create the debug dialog out of process to avoid the crashes caused by
376 * Windows events leaking into our event loop from an in process dialog.
377 * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg).
378 * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792
380 PROCESS_INFORMATION pi;
381 STARTUPINFOW si;
382 PRUnichar executable[MAX_PATH];
383 PRUnichar* pName;
385 memset(&pi, 0, sizeof(pi));
387 memset(&si, 0, sizeof(si));
388 si.cb = sizeof(si);
389 si.wShowWindow = SW_SHOW;
391 // 2nd arg of CreateProcess is in/out
392 PRUnichar *msgCopy = (PRUnichar*) _alloca((strlen(aMsg) + 1)*sizeof(PRUnichar));
393 wcscpy(msgCopy , (PRUnichar*)NS_ConvertUTF8toUTF16(aMsg).get());
395 if(GetModuleFileNameW(GetModuleHandleW(L"xpcom.dll"), (LPWCH)executable, MAX_PATH) &&
396 NULL != (pName = wcsrchr(executable, '\\')) &&
397 NULL !=
398 wcscpy((WCHAR*)
399 pName+1, L"windbgdlg.exe") &&
400 CreateProcessW((LPCWSTR)executable, (LPWSTR)msgCopy, NULL, NULL, PR_FALSE,
401 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
402 NULL, NULL, &si, &pi)) {
403 WaitForSingleObject(pi.hProcess, INFINITE);
404 GetExitCodeProcess(pi.hProcess, &code);
405 CloseHandle(pi.hProcess);
406 CloseHandle(pi.hThread);
409 switch(code) {
410 case IDABORT:
411 //This should exit us
412 raise(SIGABRT);
413 //If we are ignored exit this way..
414 _exit(3);
416 case IDIGNORE:
417 return;
421 ::DebugBreak();
423 #endif // WINCE
424 #elif defined(XP_OS2)
425 char msg[1200];
426 PR_snprintf(msg, sizeof(msg),
427 "%s\n\nClick Cancel to Debug Application.\n"
428 "Click Enter to continue running the Application.", aMsg);
429 ULONG code = MBID_ERROR;
430 code = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, msg,
431 "NSGlue_Assertion", 0,
432 MB_ERROR | MB_ENTERCANCEL);
434 /* It is possible that we are executing on a thread that doesn't have a
435 * message queue. In that case, the message won't appear, and code will
436 * be 0xFFFF. We'll give the user a chance to debug it by calling
437 * Break()
438 * Actually, that's a really bad idea since this happens a lot with threadsafe
439 * assertions and since it means that you can't actually run the debug build
440 * outside a debugger without it crashing constantly.
442 if (( code == MBID_ENTER ) || (code == MBID_ERROR))
443 return;
445 asm("int $3");
446 #elif defined(XP_BEOS)
447 DEBUGGER(aMsg);
448 #elif defined(XP_MACOSX)
449 /* Note that we put this Mac OS X test above the GNUC/x86 test because the
450 * GNUC/x86 test is also true on Intel Mac OS X and we want the PPC/x86
451 * impls to be the same.
453 raise(SIGTRAP);
454 #elif defined(__GNUC__) && (defined(__i386__) || defined(__i386) || defined(__x86_64__))
455 asm("int $3");
456 #else
457 // don't know how to break on this platform
458 #endif
461 static const nsDebugImpl kImpl;
463 NS_METHOD
464 nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
466 NS_ENSURE_NO_AGGREGATION(outer);
468 return const_cast<nsDebugImpl*>(&kImpl)->
469 QueryInterface(aIID, aInstancePtr);
472 ////////////////////////////////////////////////////////////////////////////////
474 NS_COM nsresult
475 NS_ErrorAccordingToNSPR()
477 PRErrorCode err = PR_GetError();
478 switch (err) {
479 case PR_OUT_OF_MEMORY_ERROR: return NS_ERROR_OUT_OF_MEMORY;
480 case PR_WOULD_BLOCK_ERROR: return NS_BASE_STREAM_WOULD_BLOCK;
481 case PR_FILE_NOT_FOUND_ERROR: return NS_ERROR_FILE_NOT_FOUND;
482 case PR_READ_ONLY_FILESYSTEM_ERROR: return NS_ERROR_FILE_READ_ONLY;
483 case PR_NOT_DIRECTORY_ERROR: return NS_ERROR_FILE_NOT_DIRECTORY;
484 case PR_IS_DIRECTORY_ERROR: return NS_ERROR_FILE_IS_DIRECTORY;
485 case PR_LOOP_ERROR: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK;
486 case PR_FILE_EXISTS_ERROR: return NS_ERROR_FILE_ALREADY_EXISTS;
487 case PR_FILE_IS_LOCKED_ERROR: return NS_ERROR_FILE_IS_LOCKED;
488 case PR_FILE_TOO_BIG_ERROR: return NS_ERROR_FILE_TOO_BIG;
489 case PR_NO_DEVICE_SPACE_ERROR: return NS_ERROR_FILE_NO_DEVICE_SPACE;
490 case PR_NAME_TOO_LONG_ERROR: return NS_ERROR_FILE_NAME_TOO_LONG;
491 case PR_DIRECTORY_NOT_EMPTY_ERROR: return NS_ERROR_FILE_DIR_NOT_EMPTY;
492 case PR_NO_ACCESS_RIGHTS_ERROR: return NS_ERROR_FILE_ACCESS_DENIED;
493 default: return NS_ERROR_FAILURE;
497 ////////////////////////////////////////////////////////////////////////////////