@@ -3219,6 +3219,89 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
32193219 _Py_COMP_DIAG_POP
32203220}
32213221
3222+ struct simpletracer_data {
3223+ int create_count ;
3224+ int destroy_count ;
3225+ void * addresses [10 ];
3226+ };
3227+
3228+ static int _simpletracer (PyObject * obj , PyRefTracerEvent event , void * data ) {
3229+ struct simpletracer_data * the_data = (struct simpletracer_data * )data ;
3230+ assert (the_data -> create_count + the_data -> destroy_count < (int )Py_ARRAY_LENGTH (the_data -> addresses ));
3231+ the_data -> addresses [the_data -> create_count + the_data -> destroy_count ] = obj ;
3232+ if (event == PyRefTracer_CREATE ) {
3233+ the_data -> create_count ++ ;
3234+ } else {
3235+ the_data -> destroy_count ++ ;
3236+ }
3237+ return 0 ;
3238+ }
3239+
3240+ static PyObject *
3241+ test_reftracer (PyObject * ob , PyObject * Py_UNUSED (ignored ))
3242+ {
3243+ // Save the current tracer and data to restore it later
3244+ void * current_data ;
3245+ PyRefTracer current_tracer = PyRefTracer_GetTracer (& current_data );
3246+
3247+ struct simpletracer_data tracer_data = {0 };
3248+ void * the_data = & tracer_data ;
3249+ // Install a simple tracer function
3250+ if (PyRefTracer_SetTracer (_simpletracer , the_data ) != 0 ) {
3251+ goto failed ;
3252+ }
3253+
3254+ // Check that the tracer was correctly installed
3255+ void * data ;
3256+ if (PyRefTracer_GetTracer (& data ) != _simpletracer || data != the_data ) {
3257+ PyErr_SetString (PyExc_AssertionError , "The reftracer not correctly installed" );
3258+ (void )PyRefTracer_SetTracer (NULL , NULL );
3259+ goto failed ;
3260+ }
3261+
3262+ // Create a bunch of objects
3263+ PyObject * obj = PyList_New (0 );
3264+ if (obj == NULL ) {
3265+ goto failed ;
3266+ }
3267+ PyObject * obj2 = PyDict_New ();
3268+ if (obj2 == NULL ) {
3269+ Py_DECREF (obj );
3270+ goto failed ;
3271+ }
3272+
3273+ // Kill all objects
3274+ Py_DECREF (obj );
3275+ Py_DECREF (obj2 );
3276+
3277+ // Remove the tracer
3278+ (void )PyRefTracer_SetTracer (NULL , NULL );
3279+
3280+ // Check that the tracer was removed
3281+ if (PyRefTracer_GetTracer (& data ) != NULL || data != NULL ) {
3282+ PyErr_SetString (PyExc_ValueError , "The reftracer was not correctly removed" );
3283+ goto failed ;
3284+ }
3285+
3286+ if (tracer_data .create_count != 2 ||
3287+ tracer_data .addresses [0 ] != obj ||
3288+ tracer_data .addresses [1 ] != obj2 ) {
3289+ PyErr_SetString (PyExc_ValueError , "The object creation was not correctly traced" );
3290+ goto failed ;
3291+ }
3292+
3293+ if (tracer_data .destroy_count != 2 ||
3294+ tracer_data .addresses [2 ] != obj ||
3295+ tracer_data .addresses [3 ] != obj2 ) {
3296+ PyErr_SetString (PyExc_ValueError , "The object destruction was not correctly traced" );
3297+ goto failed ;
3298+ }
3299+ PyRefTracer_SetTracer (current_tracer , current_data );
3300+ Py_RETURN_NONE ;
3301+ failed :
3302+ PyRefTracer_SetTracer (current_tracer , current_data );
3303+ return NULL ;
3304+ }
32223305
32233306static PyMethodDef TestMethods [] = {
32243307 {"set_errno" , set_errno , METH_VARARGS },
@@ -3257,6 +3340,7 @@ static PyMethodDef TestMethods[] = {
32573340 {"get_type_fullyqualname" , get_type_fullyqualname , METH_O },
32583341 {"get_type_module_name" , get_type_module_name , METH_O },
32593342 {"test_get_type_dict" , test_get_type_dict , METH_NOARGS },
3343+ {"test_reftracer" , test_reftracer , METH_NOARGS },
32603344 {"_test_thread_state" , test_thread_state , METH_VARARGS },
32613345#ifndef MS_WINDOWS
32623346 {"_spawn_pthread_waiter" , spawn_pthread_waiter , METH_NOARGS },
0 commit comments