1 // -*- Mode: C++; -*-
2 // Package : omniORBpy
3 // pyExceptions.cc Created on: 1999/07/29
4 // Author : Duncan Grisby (dpg1)
5 //
6 // Copyright (C) 2003-2014 Apasphere Ltd
7 // Copyright (C) 1999 AT&T Laboratories Cambridge
8 //
9 // This file is part of the omniORBpy library
10 //
11 // The omniORBpy library is free software; you can redistribute it
12 // and/or modify it under the terms of the GNU Lesser General
13 // Public License as published by the Free Software Foundation;
14 // either version 2.1 of the License, or (at your option) any later
15 // version.
16 //
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library. If not, see http://www.gnu.org/licenses/
24 //
25 //
26 // Description:
27 // Exception handling functions
28
29 #include <omnipy.h>
30 #include <pyThreadCache.h>
31
32
33 void
raise(const char * file,int line,CORBA::ULong minor,CORBA::CompletionStatus completed,PyObject * message)34 Py_BAD_PARAM::raise(const char* file, int line,
35 CORBA::ULong minor, CORBA::CompletionStatus completed,
36 PyObject* message)
37 {
38 if (omniORB::traceExceptions) {
39 omniORB::logger log;
40 log << "throw BAD_PARAM from " << _OMNI_NS(omniExHelper)::strip(file)
41 << ":" << line << " (";
42
43 const char* description =
44 _OMNI_NS(minorCode2String)(_OMNI_NS(BAD_PARAM_LookupTable),minor);
45
46 if (description) {
47 log << omniORB::logger::exceptionStatus(completed, description) << ")\n";
48 }
49 else {
50 log << omniORB::logger::exceptionStatus(completed, minor) << ")\n";
51 }
52 }
53 throw Py_BAD_PARAM(minor, completed, message);
54 }
55
56 CORBA::Exception*
_NP_duplicate() const57 Py_BAD_PARAM::_NP_duplicate() const
58 {
59 return new Py_BAD_PARAM(*this);
60 }
61
62 void
_raise() const63 Py_BAD_PARAM::_raise() const
64 {
65 throw *this;
66 }
67
68 const char*
_NP_typeId() const69 Py_BAD_PARAM::_NP_typeId() const
70 {
71 return "Exception/SystemException/BAD_PARAM/Py_BAD_PARAM";
72 }
73
74 Py_BAD_PARAM*
_downcast(CORBA::Exception * e)75 Py_BAD_PARAM::_downcast(CORBA::Exception* e)
76 {
77 return (Py_BAD_PARAM*)
78 _NP_is_a(e, "Exception/SystemException/BAD_PARAM/Py_BAD_PARAM");
79 }
80
81
82 PyObject*
handleSystemException(const CORBA::SystemException & ex,PyObject * info)83 omniPy::handleSystemException(const CORBA::SystemException& ex, PyObject* info)
84 {
85 int dummy;
86 PyObject* excc = PyDict_GetItemString(pyCORBAsysExcMap,
87 (char*)ex._NP_repoId(&dummy));
88 OMNIORB_ASSERT(excc);
89
90 PyObject* exca;
91 if (info) {
92 exca = Py_BuildValue((char*)"(iiO)", ex.minor(), ex.completed(), info);
93
94 if (omniORB::traceExceptions) {
95 PyObject* info_repr = PyObject_Repr(info);
96 omniORB::logger log;
97 log << "BAD_PARAM info: " << String_AsString(info_repr) << "\n";
98 Py_DECREF(info_repr);
99 }
100 }
101 else {
102 exca = Py_BuildValue((char*)"(ii)", ex.minor(), ex.completed());
103 }
104
105 PyObject* exci = PyEval_CallObject(excc, exca);
106 Py_DECREF(exca);
107 if (exci) {
108 // If we couldn't create the exception object, there will be a
109 // suitable error set already
110 PyErr_SetObject(excc, exci);
111 Py_DECREF(exci);
112 }
113 return 0;
114 }
115
116 PyObject*
createPySystemException(const CORBA::SystemException & ex)117 omniPy::createPySystemException(const CORBA::SystemException& ex)
118 {
119 int dummy;
120 PyObject* excc = PyDict_GetItemString(pyCORBAsysExcMap,
121 (char*)ex._NP_repoId(&dummy));
122 OMNIORB_ASSERT(excc);
123
124 PyObject* exca = Py_BuildValue((char*)"(ii)", ex.minor(), ex.completed());
125 PyObject* exci = PyEval_CallObject(excc, exca);
126 Py_DECREF(exca);
127
128 return exci;
129 }
130
131
132 void
produceSystemException(PyObject * eobj,PyObject * erepoId,PyObject * etype,PyObject * etraceback)133 omniPy::produceSystemException(PyObject* eobj, PyObject* erepoId,
134 PyObject* etype, PyObject* etraceback)
135 {
136 CORBA::ULong minor = 0;
137 CORBA::CompletionStatus status = CORBA::COMPLETED_MAYBE;
138
139 PyRefHolder m(PyObject_GetAttrString(eobj, (char*)"minor"));
140 PyRefHolder c(PyObject_GetAttrString(eobj, (char*)"completed"));
141
142 try {
143 if (m.valid())
144 minor = getULongVal(m);
145
146 if (c.valid())
147 status = (CORBA::CompletionStatus)getEnumVal(c);
148 }
149 catch (Py_BAD_PARAM& bp) {
150 bp.logInfoAndDrop("Invalid data inside system exception");
151 }
152
153 // Clear any errors raised by the GetAttrs
154 if (PyErr_Occurred()) PyErr_Clear();
155
156 const char* repoId = String_AS_STRING(erepoId);
157
158 #define THROW_SYSTEM_EXCEPTION_IF_MATCH(ex) \
159 if (omni::strMatch(repoId, "IDL:omg.org/CORBA/" #ex ":1.0")) { \
160 if (omniORB::traceExceptions) { \
161 { \
162 PyObject* erepr = PyObject_Repr(eobj); \
163 omniORB::logger l; \
164 l << "Caught a CORBA system exception during up-call: " \
165 << String_AsString(erepr) << "\n"; \
166 Py_DECREF(erepr); \
167 } \
168 PyErr_Restore(etype, eobj, etraceback); \
169 PyErr_Print(); \
170 } \
171 else { \
172 Py_XDECREF(eobj); Py_DECREF(etype); Py_XDECREF(etraceback); \
173 } \
174 Py_DECREF(erepoId); \
175 OMNIORB_THROW(ex, minor, status); \
176 }
177
178 OMNIORB_FOR_EACH_SYS_EXCEPTION(THROW_SYSTEM_EXCEPTION_IF_MATCH)
179
180 #undef THROW_SYSTEM_EXCEPTION_IF_MATCH
181
182 if (omniORB::trace(1)) {
183 {
184 PyObject* erepr = PyObject_Repr(eobj);
185 omniORB::logger l;
186 l << "Caught an unexpected CORBA exception during up-call: "
187 << String_AsString(erepr) << "\n";
188 Py_DECREF(erepr);
189 }
190 PyErr_Restore(etype, eobj, etraceback);
191 PyErr_Print();
192 }
193 else {
194 Py_XDECREF(eobj); Py_DECREF(etype); Py_XDECREF(etraceback);
195 }
196 Py_DECREF(erepoId);
197
198 if (m.valid() && c.valid())
199 OMNIORB_THROW(UNKNOWN, UNKNOWN_SystemException, CORBA::COMPLETED_MAYBE);
200 else
201 OMNIORB_THROW(UNKNOWN, UNKNOWN_UserException, CORBA::COMPLETED_MAYBE);
202 }
203
204
205 void
handlePythonException()206 omniPy::handlePythonException()
207 {
208 OMNIORB_ASSERT(PyErr_Occurred());
209
210 PyObject *etype, *evalue, *etraceback;
211 PyObject *erepoId = 0;
212 PyErr_Fetch(&etype, &evalue, &etraceback);
213 PyErr_NormalizeException(&etype, &evalue, &etraceback);
214 OMNIORB_ASSERT(etype);
215
216 if (evalue)
217 erepoId = PyObject_GetAttrString(evalue, (char*)"_NP_RepositoryId");
218
219 if (!(erepoId && String_Check(erepoId))) {
220 PyErr_Clear();
221 Py_XDECREF(erepoId);
222 if (omniORB::trace(1)) {
223 {
224 omniORB::logger l;
225 l << "Caught an unexpected Python exception during up-call.\n";
226 }
227 PyErr_Restore(etype, evalue, etraceback);
228 PyErr_Print();
229 }
230 OMNIORB_THROW(UNKNOWN, UNKNOWN_PythonException,
231 CORBA::COMPLETED_MAYBE);
232 }
233
234 // Is it a LOCATION_FORWARD?
235 if (omni::strMatch(String_AS_STRING(erepoId), "omniORB.LOCATION_FORWARD")) {
236 Py_DECREF(erepoId); Py_DECREF(etype); Py_XDECREF(etraceback);
237 omniPy::handleLocationForward(evalue);
238 }
239
240 // System exception
241 omniPy::produceSystemException(evalue, erepoId, etype, etraceback);
242 }
243
244
245 PyObject*
raiseScopedException(PyObject * module,const char * scope,const char * cls)246 omniPy::raiseScopedException(PyObject* module, const char* scope,
247 const char* cls)
248 {
249 omniPy::PyRefHolder excs(PyObject_GetAttrString(module, (char*)scope));
250 omniPy::PyRefHolder excc(PyObject_GetAttrString(excs, (char*)cls));
251 omniPy::PyRefHolder exci(PyObject_CallObject(excc, omniPy::pyEmptyTuple));
252
253 PyErr_SetObject(excc, exci);
254 return 0;
255 }
256
257
258 void
handleLocationForward(PyObject * evalue)259 omniPy::handleLocationForward(PyObject* evalue)
260 {
261 PyObject* pyfwd = PyObject_GetAttrString(evalue, (char*)"_forward");
262 PyObject* pyperm = PyObject_GetAttrString(evalue, (char*)"_perm");
263 OMNIORB_ASSERT(pyfwd);
264 OMNIORB_ASSERT(pyperm);
265
266 CORBA::Boolean perm = PyObject_IsTrue(pyperm);
267
268 if (PyErr_Occurred()) {
269 perm = 0;
270
271 if (omniORB::trace(1)) {
272 omniORB::logs(1, "Invalid 'permanent' attribute in LOCATION_FORWARD.");
273 PyErr_Print();
274 }
275 else
276 PyErr_Clear();
277 }
278
279 CORBA::Object_ptr fwd = omniPy::getObjRef(pyfwd);
280
281 if (fwd)
282 CORBA::Object::_duplicate(fwd);
283
284 Py_DECREF(pyfwd);
285 Py_DECREF(pyperm);
286 Py_DECREF(evalue);
287
288 if (fwd) {
289 OMNIORB_ASSERT(CORBA::Object::_PR_is_valid(fwd));
290 throw omniORB::LOCATION_FORWARD(fwd, perm);
291 }
292 else {
293 omniORB::logs(1, "Invalid object reference inside "
294 "omniORB.LOCATION_FORWARD exception");
295 OMNIORB_THROW(BAD_PARAM, BAD_PARAM_WrongPythonType, CORBA::COMPLETED_NO);
296 }
297 }
298
299
300
301 //
302 // Implementation of PyUserException
303 //
304
305 omniPy::
PyUserException(PyObject * desc)306 PyUserException::PyUserException(PyObject* desc)
307 : desc_(desc), exc_(0), decref_on_del_(0)
308 {
309 OMNIORB_ASSERT(desc_);
310 pd_insertToAnyFn = 0;
311 pd_insertToAnyFnNCP = 0;
312
313 if (omniORB::trace(25)) {
314 omniORB::logger l;
315 const char* repoId = String_AS_STRING(PyTuple_GET_ITEM(desc_, 2));
316 l << "Prepare to unmarshal Python user exception " << repoId << "\n";
317 }
318 }
319
320 omniPy::
PyUserException(PyObject * desc,PyObject * exc,CORBA::CompletionStatus comp_status)321 PyUserException::PyUserException(PyObject* desc, PyObject* exc,
322 CORBA::CompletionStatus comp_status)
323 : desc_(desc), exc_(exc), decref_on_del_(1)
324 {
325 OMNIORB_ASSERT(desc_);
326 OMNIORB_ASSERT(exc_);
327
328 if (omniORB::trace(25)) {
329 omniORB::logger l;
330 const char* repoId = String_AS_STRING(PyTuple_GET_ITEM(desc_, 2));
331 l << "Construct Python user exception " << repoId << "\n";
332 }
333
334 try {
335 omniPy::validateType(desc_, exc_, comp_status);
336 }
337 catch (...) {
338 Py_DECREF(exc_);
339 throw;
340 }
341
342 pd_insertToAnyFn = 0;
343 pd_insertToAnyFnNCP = 0;
344 }
345
346 omniPy::
PyUserException(const PyUserException & e)347 PyUserException::PyUserException(const PyUserException& e)
348 : desc_(e.desc_), exc_(e.exc_), decref_on_del_(1)
349 {
350 pd_insertToAnyFn = 0;
351 pd_insertToAnyFnNCP = 0;
352
353 // Oh dear. We need to mark the exception being copied to say that
354 // the exception object should not be DECREF'd when it is deleted.
355 ((PyUserException&)e).decref_on_del_ = 0;
356 }
357
358 omniPy::
~PyUserException()359 PyUserException::~PyUserException()
360 {
361 if (decref_on_del_) {
362 if (omniORB::trace(25)) {
363 omniORB::logger l;
364 const char* repoId = String_AS_STRING(PyTuple_GET_ITEM(desc_, 2));
365 l << "Python user exception state " << repoId << " dropped unused\n";
366 }
367 omnipyThreadCache::lock _t;
368 OMNIORB_ASSERT(exc_);
369 Py_DECREF(exc_);
370 }
371 }
372
373 PyObject*
374 omniPy::
setPyExceptionState()375 PyUserException::setPyExceptionState()
376 {
377 OMNIORB_ASSERT(desc_);
378 OMNIORB_ASSERT(exc_);
379
380 PyObject* excclass = PyTuple_GET_ITEM(desc_, 1);
381
382 if (omniORB::trace(25)) {
383 omniORB::logger l;
384 const char* repoId = String_AS_STRING(PyTuple_GET_ITEM(desc_, 2));
385 l << "Set Python user exception state " << repoId << "\n";
386 }
387 PyErr_SetObject(excclass, exc_);
388 Py_DECREF(exc_);
389 decref_on_del_ = 0;
390 exc_ = 0;
391 return 0;
392 }
393
394 void
395 omniPy::
decrefPyException()396 PyUserException::decrefPyException()
397 {
398 OMNIORB_ASSERT(exc_);
399 Py_DECREF(exc_);
400 decref_on_del_ = 0;
401 exc_ = 0;
402 }
403
404
405 void
406 omniPy::
operator >>=(cdrStream & stream) const407 PyUserException::operator>>=(cdrStream& stream) const
408 {
409 OMNIORB_ASSERT(exc_);
410
411 if (omniORB::trace(25)) {
412 omniORB::logger l;
413 const char* repoId = String_AS_STRING(PyTuple_GET_ITEM(desc_, 2));
414 l << "Marshal Python user exception " << repoId << "\n";
415 }
416
417 PyUnlockingCdrStream pystream(stream);
418
419 int cnt = (PyTuple_GET_SIZE(desc_) - 4) / 2;
420
421 PyObject* name;
422 PyObject* value;
423
424 int i, j;
425 for (i=0,j=4; i < cnt; i++) {
426 name = PyTuple_GET_ITEM(desc_, j++);
427 value = PyObject_GetAttr(exc_, name);
428 Py_DECREF(value); // Exception object still holds a reference.
429 omniPy::marshalPyObject(pystream, PyTuple_GET_ITEM(desc_, j++), value);
430 }
431 }
432
433 void
434 omniPy::
operator <<=(cdrStream & stream)435 PyUserException::operator<<=(cdrStream& stream)
436 {
437 if (omniORB::trace(25)) {
438 omniORB::logger l;
439 const char* repoId = String_AS_STRING(PyTuple_GET_ITEM(desc_, 2));
440 l << "Unmarshal Python user exception " << repoId << "\n";
441 }
442
443 PyUnlockingCdrStream pystream(stream);
444
445 PyObject* excclass = PyTuple_GET_ITEM(desc_, 1);
446
447 int cnt = (PyTuple_GET_SIZE(desc_) - 4) / 2;
448 PyObject* exctuple = PyTuple_New(cnt);
449 omniPy::PyRefHolder exctuple_holder(exctuple);
450
451 int i, j;
452 for (i=0, j=5; i < cnt; i++, j+=2) {
453 PyTuple_SET_ITEM(exctuple, i,
454 unmarshalPyObject(pystream,
455 PyTuple_GET_ITEM(desc_, j)));
456 }
457 exc_ = PyEval_CallObject(excclass, exctuple);
458
459 if (!exc_) {
460 // Oh dear. Python exception constructor threw an exception.
461 if (omniORB::trace(1)) {
462 {
463 omniORB::logger l;
464 l << "Caught unexpected error trying to create an exception:\n";
465 }
466 PyErr_Print();
467 }
468 else
469 PyErr_Clear();
470
471 OMNIORB_THROW(INTERNAL, 0, CORBA::COMPLETED_MAYBE);
472 }
473 }
474
475 void
476 omniPy::
_raise() const477 PyUserException::_raise() const
478 {
479 OMNIORB_ASSERT(desc_);
480 OMNIORB_ASSERT(exc_);
481
482 if (omniORB::trace(25)) {
483 omniORB::logger l;
484 const char* repoId = String_AS_STRING(PyTuple_GET_ITEM(desc_, 2));
485 l << "C++ throw of Python user exception " << repoId << "\n";
486 }
487 throw *this;
488 }
489
490 const char*
491 omniPy::
_NP_repoId(int * size) const492 PyUserException::_NP_repoId(int* size) const
493 {
494 PyObject* pyrepoId = PyTuple_GET_ITEM(desc_, 2);
495 OMNIORB_ASSERT(String_Check(pyrepoId));
496
497 CORBA::ULong len;
498 const char* repoId = String_AS_STRING_AND_SIZE(pyrepoId, len);
499
500 *size = len + 1;
501 return repoId;
502 }
503
504 void
505 omniPy::
_NP_marshal(cdrStream & stream) const506 PyUserException::_NP_marshal(cdrStream& stream) const
507 {
508 omnipyThreadCache::lock _t;
509 *this >>= stream;
510 }
511
512 CORBA::Exception*
513 omniPy::
_NP_duplicate() const514 PyUserException::_NP_duplicate() const
515 {
516 return new PyUserException(*this);
517 }
518
519 const char*
520 omniPy::PyUserException::
521 _PD_typeId = "Exception/UserException/omniPy::PyUserException";
522
523 const char*
524 omniPy::
_NP_typeId() const525 PyUserException::_NP_typeId() const
526 {
527 return _PD_typeId;
528 }
529
530 omniPy::PyUserException*
_downcast(CORBA::Exception * ex)531 omniPy::PyUserException::_downcast(CORBA::Exception* ex)
532 {
533 return (omniPy::PyUserException*)_NP_is_a(ex, _PD_typeId);
534 }
535
536 const omniPy::PyUserException*
_downcast(const CORBA::Exception * ex)537 omniPy::PyUserException::_downcast(const CORBA::Exception* ex)
538 {
539 return (const omniPy::PyUserException*)_NP_is_a(ex, _PD_typeId);
540 }
541