Back to index

lightning-sunbird  0.9+nobinonly
ErrorUtils.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Python XPCOM language bindings.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * ActiveState Tool Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Mark Hammond <MarkH@ActiveState.com> (original author)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 //
00039 // This code is part of the XPCOM extensions for Python.
00040 //
00041 // Written May 2000 by Mark Hammond.
00042 //
00043 // Based heavily on the Python COM support, which is
00044 // (c) Mark Hammond and Greg Stein.
00045 //
00046 // (c) 2000, ActiveState corp.
00047 
00048 #include "PyXPCOM_std.h"
00049 #include "nsReadableUtils.h"
00050 #include <nsIConsoleService.h>
00051 #include "nspr.h" // PR_fprintf
00052 
00053 static char *PyTraceback_AsString(PyObject *exc_tb);
00054 
00055 // The internal helper that actually moves the
00056 // formatted string to the target!
00057 
00058 void LogMessage(const char *prefix, const char *pszMessageText)
00059 {
00060        nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
00061        NS_ABORT_IF_FALSE(consoleService, "Where is the console service?");
00062        if (consoleService)
00063               consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(pszMessageText).get());
00064        else
00065               PR_fprintf(PR_STDERR,"%s\n", pszMessageText);
00066 }
00067 
00068 void LogMessage(const char *prefix, nsACString &text)
00069 {
00070        char *c = ToNewCString(text);
00071        LogMessage(prefix, c);
00072        nsCRT::free(c);
00073 }
00074 
00075 // A helper for the various logging routines.
00076 static void VLogF(const char *prefix, const char *fmt, va_list argptr)
00077 {
00078        char buff[512];
00079 
00080        vsprintf(buff, fmt, argptr);
00081 
00082        LogMessage(prefix, buff);
00083 }
00084 
00085 void PyXPCOM_LogError(const char *fmt, ...)
00086 {
00087        va_list marker;
00088        va_start(marker, fmt);
00089        VLogF("PyXPCOM Error: ", fmt, marker);
00090        // If we have a Python exception, also log that:
00091        PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL;
00092        PyErr_Fetch( &exc_typ, &exc_val, &exc_tb);
00093        if (exc_typ) {
00094               PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb);
00095               nsCAutoString streamout;
00096 
00097               if (exc_tb) {
00098                      const char *szTraceback = PyTraceback_AsString(exc_tb);
00099                      if (szTraceback == NULL)
00100                             streamout += "Can't get the traceback info!";
00101                      else {
00102                             streamout += "Traceback (most recent call last):\n";
00103                             streamout += szTraceback;
00104                             PyMem_Free((void *)szTraceback);
00105                      }
00106               }
00107               PyObject *temp = PyObject_Str(exc_typ);
00108               if (temp) {
00109                      streamout += PyString_AsString(temp);
00110                      Py_DECREF(temp);
00111               } else
00112                      streamout += "Can't convert exception to a string!";
00113               streamout += ": ";
00114               if (exc_val != NULL) {
00115                      temp = PyObject_Str(exc_val);
00116                      if (temp) {
00117                             streamout += PyString_AsString(temp);
00118                             Py_DECREF(temp);
00119                      } else
00120                             streamout += "Can't convert exception value to a string!";
00121               }
00122               streamout += "\n";
00123               LogMessage("PyXPCOM Exception:", streamout);
00124        }
00125        PyErr_Restore(exc_typ, exc_val, exc_tb);
00126 }
00127 
00128 void PyXPCOM_LogWarning(const char *fmt, ...)
00129 {
00130        va_list marker;
00131        va_start(marker, fmt);
00132        VLogF("PyXPCOM Warning: ", fmt, marker);
00133 }
00134 
00135 #ifdef DEBUG
00136 void PyXPCOM_LogDebug(const char *fmt, ...)
00137 {
00138        va_list marker;
00139        va_start(marker, fmt);
00140        VLogF("PyXPCOM Debug: ", fmt, marker);
00141 }
00142 #endif
00143 
00144 
00145 PyObject *PyXPCOM_BuildPyException(nsresult r)
00146 {
00147        // Need the message etc.
00148        PyObject *evalue = Py_BuildValue("i", r);
00149        PyErr_SetObject(PyXPCOM_Error, evalue);
00150        Py_XDECREF(evalue);
00151        return NULL;
00152 }
00153 
00154 nsresult PyXPCOM_SetCOMErrorFromPyException()
00155 {
00156        if (!PyErr_Occurred())
00157               // No error occurred
00158               return NS_OK;
00159        return NS_ERROR_FAILURE;
00160 }
00161 
00162 /* Obtains a string from a Python traceback.
00163    This is the exact same string as "traceback.print_exc" would return.
00164 
00165    Pass in a Python traceback object (probably obtained from PyErr_Fetch())
00166    Result is a string which must be free'd using PyMem_Free()
00167 */
00168 #define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}
00169 
00170 char *PyTraceback_AsString(PyObject *exc_tb)
00171 {
00172        char *errMsg = NULL; /* holds a local error message */
00173        char *result = NULL; /* a valid, allocated result. */
00174        PyObject *modStringIO = NULL;
00175        PyObject *modTB = NULL;
00176        PyObject *obFuncStringIO = NULL;
00177        PyObject *obStringIO = NULL;
00178        PyObject *obFuncTB = NULL;
00179        PyObject *argsTB = NULL;
00180        PyObject *obResult = NULL;
00181 
00182        /* Import the modules we need - cStringIO and traceback */
00183        modStringIO = PyImport_ImportModule("cStringIO");
00184        if (modStringIO==NULL)
00185               TRACEBACK_FETCH_ERROR("cant import cStringIO\n");
00186 
00187        modTB = PyImport_ImportModule("traceback");
00188        if (modTB==NULL)
00189               TRACEBACK_FETCH_ERROR("cant import traceback\n");
00190        /* Construct a cStringIO object */
00191        obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
00192        if (obFuncStringIO==NULL)
00193               TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n");
00194        obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
00195        if (obStringIO==NULL)
00196               TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n");
00197        /* Get the traceback.print_exception function, and call it. */
00198        obFuncTB = PyObject_GetAttrString(modTB, "print_tb");
00199        if (obFuncTB==NULL)
00200               TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n");
00201 
00202        argsTB = Py_BuildValue("OOO", 
00203                      exc_tb  ? exc_tb  : Py_None,
00204                      Py_None, 
00205                      obStringIO);
00206        if (argsTB==NULL) 
00207               TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n");
00208 
00209        obResult = PyObject_CallObject(obFuncTB, argsTB);
00210        if (obResult==NULL) 
00211               TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n");
00212        /* Now call the getvalue() method in the StringIO instance */
00213        Py_DECREF(obFuncStringIO);
00214        obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
00215        if (obFuncStringIO==NULL)
00216               TRACEBACK_FETCH_ERROR("cant find getvalue function\n");
00217        Py_DECREF(obResult);
00218        obResult = PyObject_CallObject(obFuncStringIO, NULL);
00219        if (obResult==NULL) 
00220               TRACEBACK_FETCH_ERROR("getvalue() failed.\n");
00221 
00222        /* And it should be a string all ready to go - duplicate it. */
00223        if (!PyString_Check(obResult))
00224                      TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n");
00225 
00226        { // a temp scope so I can use temp locals.
00227        char *tempResult = PyString_AsString(obResult);
00228        result = (char *)PyMem_Malloc(strlen(tempResult)+1);
00229        if (result==NULL)
00230               TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string\n");
00231 
00232        strcpy(result, tempResult);
00233        } // end of temp scope.
00234 done:
00235        /* All finished - first see if we encountered an error */
00236        if (result==NULL && errMsg != NULL) {
00237               result = (char *)PyMem_Malloc(strlen(errMsg)+1);
00238               if (result != NULL)
00239                      /* if it does, not much we can do! */
00240                      strcpy(result, errMsg);
00241        }
00242        Py_XDECREF(modStringIO);
00243        Py_XDECREF(modTB);
00244        Py_XDECREF(obFuncStringIO);
00245        Py_XDECREF(obStringIO);
00246        Py_XDECREF(obFuncTB);
00247        Py_XDECREF(argsTB);
00248        Py_XDECREF(obResult);
00249        return result;
00250 }
00251 
00252 // See comments in PyXPCOM.h for why we need this!
00253 void PyXPCOM_MakePendingCalls()
00254 {
00255        while (1) {
00256               int rc = Py_MakePendingCalls();
00257               if (rc == 0)
00258                      break;
00259               // An exception - just report it as normal.
00260               // Note that a traceback is very unlikely!
00261               PyXPCOM_LogError("Unhandled exception detected before entering Python.\n");
00262               PyErr_Clear();
00263               // And loop around again until we are told everything is done!
00264        }
00265 }