@@ -397,3 +397,70 @@ TEST_F(ApplicationContextTest, ClearAllIsIdempotent)
397
397
taint_engine_context->clear_all_request_context_slots ();
398
398
ASSERT_EQ (taint_engine_context->get_tainted_object_map_by_ctx_id (id), nullptr );
399
399
}
400
+
401
+ TEST_F (ApplicationContextTest, ShuttingDownBlocksStartAndLookups)
402
+ {
403
+ // Enable shutdown: all operations should early-return
404
+ TaintEngineContext::set_shutting_down (true );
405
+
406
+ // start_request_context should refuse to allocate a slot
407
+ auto idx = taint_engine_context->start_request_context ();
408
+ ASSERT_FALSE (idx.has_value ());
409
+
410
+ // Lookups should be short-circuited
411
+ py::str s (" x" );
412
+ auto m_obj = taint_engine_context->get_tainted_object_map (s.ptr ());
413
+ ASSERT_EQ (m_obj, nullptr );
414
+
415
+ std::vector<PyObject*> objs{ s.ptr () };
416
+ auto m_list = taint_engine_context->get_tainted_object_map_from_list_of_pyobjects (objs);
417
+ ASSERT_EQ (m_list, nullptr );
418
+
419
+ // By-index lookup should also be blocked
420
+ auto m_by_id = taint_engine_context->get_tainted_object_map_by_ctx_id (0 );
421
+ ASSERT_EQ (m_by_id, nullptr );
422
+
423
+ // Reset shutdown flag for following tests
424
+ TaintEngineContext::set_shutting_down (false );
425
+ }
426
+
427
+ TEST_F (ApplicationContextTest, ClearingShuttingDownRestoresOperation)
428
+ {
429
+ // Block then unblock and verify operations resume
430
+ TaintEngineContext::set_shutting_down (true );
431
+ ASSERT_FALSE (taint_engine_context->start_request_context ().has_value ());
432
+
433
+ TaintEngineContext::set_shutting_down (false );
434
+ auto idx = taint_engine_context->start_request_context ();
435
+ ASSERT_TRUE (idx.has_value ());
436
+ auto m = taint_engine_context->get_tainted_object_map_by_ctx_id (*idx);
437
+ ASSERT_NE (m, nullptr );
438
+ }
439
+
440
+ TEST_F (ApplicationContextTest, AtexitHandlerClearsAndResetsContext)
441
+ {
442
+ // Import the native module to trigger its PYBIND11_MODULE initializer,
443
+ // which registers an atexit handler that sets shutting_down=true,
444
+ // clears slots, and resets the global taint_engine_context.
445
+ auto mod = py::module::import (" ddtrace.appsec._iast._taint_tracking._native" );
446
+ auto ctx = mod.attr (" context" );
447
+
448
+ // Before running exit funcs, capacity should be > 0 (module created a context)
449
+ auto before_size = ctx.attr (" debug_context_array_size" )().cast <size_t >();
450
+ ASSERT_GT (before_size, static_cast <size_t >(0 ));
451
+
452
+ // Execute Python atexit callbacks
453
+ auto atexit = py::module::import (" atexit" );
454
+ atexit.attr (" _run_exitfuncs" )();
455
+
456
+ // After atexit, context helpers should reflect cleared/reset state
457
+ auto after_size = ctx.attr (" debug_context_array_size" )().cast <size_t >();
458
+ ASSERT_EQ (after_size, static_cast <size_t >(0 ));
459
+
460
+ // get_tainted_object_map_by_ctx_id returns bool; should be False (nullptr)
461
+ auto by_id_exists = ctx.attr (" get_tainted_object_map_by_ctx_id" )(0 ).cast <bool >();
462
+ ASSERT_FALSE (by_id_exists);
463
+
464
+ // Recreate a fresh context manually to not affect subsequent tests
465
+ taint_engine_context = std::make_unique<TaintEngineContext>();
466
+ }
0 commit comments