@@ -72,11 +72,11 @@ JPypeException::JPypeException(const JPypeException &ex) noexcept
72
72
73
73
JPypeException& JPypeException::operator = (const JPypeException& ex)
74
74
{
75
- if (this == &ex)
76
- {
77
- return *this ;
78
- }
79
- m_Context = ex.m_Context ;
75
+ if (this == &ex)
76
+ {
77
+ return *this ;
78
+ }
79
+ m_Context = ex.m_Context ;
80
80
m_Type = ex.m_Type ;
81
81
m_Trace = ex.m_Trace ;
82
82
m_Throwable = ex.m_Throwable ;
@@ -88,9 +88,40 @@ JPypeException& JPypeException::operator = (const JPypeException& ex)
88
88
void JPypeException::from (const JPStackInfo& info)
89
89
{
90
90
JP_TRACE (" EXCEPTION FROM: " , info.getFile (), info.getLine ());
91
- m_Trace.emplace_back (info);
91
+ m_Trace.push_back (info);
92
92
}
93
93
94
+ // Okay from this point on we have to suit up in full Kevlar because
95
+ // this code must handle every conceivable and still reach a resolution.
96
+ // Exceptions may be throws during initialization where only a fraction
97
+ // of the resources are available, during the middle of normal operation,
98
+ // or worst of all as the system is being yanked out from under us during
99
+ // shutdown. Each and every one of these cases must be considered.
100
+ // Further each and every function called here must be hardened similarly
101
+ // or they will become the weak link. And remember it is not paranoia if
102
+ // they are actually out to get you.
103
+ //
104
+ // Onward my friends to victory or a glorious segfault!
105
+ /*
106
+ string JPypeException::getMessage()
107
+ {
108
+ JP_TRACE_IN("JPypeException::getMessage");
109
+ // Must be bullet proof
110
+ try
111
+ {
112
+ stringstream str;
113
+ str << m_Message << endl;
114
+ JP_TRACE(str.str());
115
+ return str.str();
116
+ // GCOVR_EXCL_START
117
+ } catch (...)
118
+ {
119
+ return "error during get message";
120
+ }
121
+ JP_TRACE_OUT;
122
+ // GCOVR_EXCL_STOP
123
+ }*/
124
+
94
125
bool isJavaThrowable (PyObject* exceptionClass)
95
126
{
96
127
JPClass* cls = PyJPClass_getJPClass (exceptionClass);
@@ -169,7 +200,7 @@ void JPypeException::convertJavaToPython()
169
200
}
170
201
// GCOVR_EXCL_STOP
171
202
172
- auto *type = (PyObject*) Py_TYPE (pyvalue.get ());
203
+ PyObject *type = (PyObject*) Py_TYPE (pyvalue.get ());
173
204
Py_INCREF (type);
174
205
175
206
// Add cause to the exception
@@ -449,83 +480,56 @@ void JPypeException::toJava(JPContext *context)
449
480
JP_TRACE_OUT; // GCOVR_EXCL_LINE
450
481
}
451
482
452
- PyTracebackObject *tb_create (
453
- PyTracebackObject *last_traceback,
483
+ PyObject *tb_create (
484
+ PyObject *last_traceback,
454
485
PyObject *dict,
455
486
const char * filename,
456
487
const char * funcname,
457
488
int linenum)
458
489
{
459
490
// Create a code for this frame. (ref count is 1)
460
- PyCodeObject * code = PyCode_NewEmpty (filename, funcname, linenum);
491
+ JPPyObject* code = JPPyObject::accept ((PyObject*) PyCode_NewEmpty (filename, funcname, linenum) );
461
492
462
493
// If we don't get the code object there is no point
463
494
if (code == nullptr )
464
495
return nullptr ;
465
496
466
- // This is a bit of a kludge. Python lacks a way to directly create
467
- // a frame from a code object except when creating from the threadstate.
468
- //
469
- // In reviewing Python implementation, I find that the only element accessed
470
- // in the thread state was the previous frame to link to. Because frame
471
- // objects change a lot between different Python versions, trying to
472
- // replicate the actions of setting up a frame is difficult to keep portable.
473
- //
474
- // Python 3.10 introduces the additional requirement that the global
475
- // dictionary supplied must have a __builtins__. We can do this once
476
- // when create the module.
477
- //
478
- // If instead we create a thread state and point the field it needs to the
479
- // previous frame we create the frames using the defined API. Much more
480
- // portable, but we have to create a big (uninitialized object) each time we
481
- // want to pass in the previous frame.
482
- PyThreadState state;
483
- if (last_traceback != nullptr )
484
- state.frame = last_traceback->tb_frame ;
485
- else
486
- state.frame = nullptr ;
487
-
488
497
// Create a frame for the traceback.
489
- PyFrameObject *frame = PyFrame_New (&state, code, dict, nullptr );
490
-
491
- // frame just borrows the reference rather than claiming it
492
- // so we need to get rid of the extra reference here.
493
- Py_DECREF (code);
494
-
498
+ PyThreadState *state = PyThreadState_GET ();
499
+ PyFrameObject *pframe = PyFrame_New (state, (PyCodeObject*) code.get (), dict, NULL );
500
+ JPPyObject frame = JPPyObject::accept ((PyObject*)pframe);
501
+
495
502
// If we don't get the frame object there is no point
496
- if (frame == nullptr )
503
+ if (frame. get () == nullptr )
497
504
return nullptr ;
498
505
499
506
// Create a traceback
500
- auto *traceback = (PyTracebackObject*)
501
- PyObject_GC_New (PyTracebackObject, &PyTraceBack_Type);
507
+ #if PY_MINOR_VERSION<11
508
+ JPPyObject lasti = JPPyObject::claim (PyLong_FromLong (pframe->f_lasti ));
509
+ #else
510
+ JPPyObject lasti = JPPyObject::claim (PyLong_FromLong (PyFrame_GetLasti (pframe)));
511
+ #endif
512
+ JPPyObject linenuma = JPPyObject::claim (PyLong_FromLong (linenum));
513
+ JPPyObject tuple = JPPyObject::call (PyTuple_Pack (4 , Py_None, frame.get (), lasti.get (), linenuma.get ()));
514
+ JPPyObject traceback = JPPyObject::accept (PyObject_Call ((PyObject*) &PyTraceBack_Type, tuple.get (), NULL ));
502
515
503
516
// We could fail in process
504
- if (traceback == nullptr )
517
+ if (traceback. get () == nullptr )
505
518
{
506
519
Py_DECREF (frame);
507
520
return nullptr ;
508
521
}
509
522
510
- // Set the fields
511
- traceback->tb_frame = frame; // Steal the reference from frame
512
- traceback->tb_lasti = frame->f_lasti ;
513
- traceback->tb_lineno = linenum;
514
- Py_XINCREF (last_traceback);
515
- traceback->tb_next = last_traceback;
516
-
517
- // Allow GC on the object
518
- PyObject_GC_Track (traceback);
519
- return traceback;
523
+ return traceback.keep ();
520
524
}
521
525
522
526
PyObject* PyTrace_FromJPStackTrace (JPStackTrace& trace)
523
527
{
524
- PyTracebackObject *last_traceback = nullptr ;
528
+ PyObject *last_traceback = nullptr ;
525
529
PyObject *dict = PyModule_GetDict (PyJPModule);
526
- for (auto & iter : trace)
530
+ for (auto & iter : trace)
527
531
{
528
- last_traceback = tb_create (last_traceback, dict, iter.getFile (),
532
+ last_traceback = tb_create (last_traceback, dict, iter.getFile (),
529
533
iter.getFunction (), iter.getLine ());
530
534
}
531
535
if (last_traceback == nullptr )
@@ -544,8 +548,8 @@ JPPyObject PyTrace_FromJavaException(JPJavaFrame& frame, jthrowable th, jthrowab
544
548
return {};
545
549
546
550
JNIEnv* env = frame.getEnv ();
547
- auto obj = ( jobjectArray) env->CallObjectMethodA (context->getJavaContext (),
548
- context->m_Context_GetStackFrameID , args);
551
+ jobjectArray obj = static_cast < jobjectArray>( env->CallObjectMethodA (context->getJavaContext (),
552
+ context->m_Context_GetStackFrameID , args)) ;
549
553
550
554
// Eat any exceptions that were generated
551
555
if (env->ExceptionCheck () == JNI_TRUE)
@@ -559,8 +563,8 @@ JPPyObject PyTrace_FromJavaException(JPJavaFrame& frame, jthrowable th, jthrowab
559
563
{
560
564
string filename, method;
561
565
auto jclassname = static_cast <jstring>(frame.GetObjectArrayElement (obj, i));
562
- auto jmethodname = ( jstring) frame.GetObjectArrayElement (obj, i + 1 );
563
- auto jfilename = ( jstring) frame.GetObjectArrayElement (obj, i + 2 );
566
+ auto jmethodname = static_cast < jstring>( frame.GetObjectArrayElement (obj, i + 1 ) );
567
+ auto jfilename = static_cast < jstring>( frame.GetObjectArrayElement (obj, i + 2 ) );
564
568
if (jfilename != nullptr )
565
569
filename = frame.toStringUTF8 (jfilename);
566
570
else
0 commit comments