Prevent unlimited recursion leading to stack overflow

This can happen notably when the user does not call ZoneEnd.

I used 256 arbitrarily as it seemed higher values would just make the UI freeze anyway due to perf reasons.
I added a warning in the notification area so that users can locate it.
This commit is contained in:
Clément Grégoire
2026-05-21 09:38:43 +02:00
parent 60247b68d3
commit 69855a1416
3 changed files with 31 additions and 0 deletions

View File

@@ -430,6 +430,12 @@ int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const V
template<typename Adapter, typename V>
int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const V& vec, int depth, bool visible, const uint32_t inheritedColor )
{
if( depth >= 256 )
{
m_worker.NotifyExcessiveZoneDepth( Adapter{}( vec.front() ).Start() );
return depth;
}
const auto vStart = ctx.vStart;
const auto vEnd = ctx.vEnd;
const auto nspx = ctx.nspx;

View File

@@ -92,6 +92,22 @@ void View::DrawNotificationArea()
TextColoredUnformatted( ImVec4( 1, 0.5, 0, 1 ), ICON_FA_EYE_DROPPER );
TooltipIfHovered( "Sampling data and ghost zones may be displayed wrongly due to data inconsistency. Save and reload the trace to fix this." );
}
if( m_worker.HasExcessiveZoneDepth() )
{
ImGui::SameLine();
TextColoredUnformatted( ImVec4( 1, 0.5, 0, 1 ), ICON_FA_LAYER_GROUP );
if( ImGui::IsItemHovered() )
{
const auto t = m_worker.GetExcessiveZoneDepthTime();
ImGui::BeginTooltip();
ImGui::TextUnformatted( "Some zones exceed the maximum nesting depth of 256 and are not displayed." );
ImGui::Separator();
TextFocused( "First occurrence:", TimeToString( t - m_worker.GetFirstTime() ) );
ImGui::TextDisabled( "Click to center the view at this time." );
ImGui::EndTooltip();
if( IsMouseClicked( 0 ) ) CenterAtTime( t );
}
}
if( m_vd.drawEmptyLabels )
{
ImGui::SameLine();

View File

@@ -678,6 +678,14 @@ public:
uint8_t GetHandshakeStatus() const { return m_handshake.load( std::memory_order_relaxed ); }
int64_t GetSamplingPeriod() const { return m_samplingPeriod; }
bool AreSamplesInconsistent() const { return m_inconsistentSamples; }
void NotifyExcessiveZoneDepth( int64_t time )
{
if( m_excessiveZoneDepthTime.load( std::memory_order_relaxed ) != -1 ) return;
int64_t expected = -1;
m_excessiveZoneDepthTime.compare_exchange_strong( expected, time, std::memory_order_relaxed );
}
int64_t GetExcessiveZoneDepthTime() const { return m_excessiveZoneDepthTime.load( std::memory_order_relaxed ); }
bool HasExcessiveZoneDepth() const { return GetExcessiveZoneDepthTime() != -1; }
static const LoadProgress& GetLoadProgress() { return s_loadProgress; }
int64_t GetLoadTime() const { return m_loadTime; }
@@ -1068,6 +1076,7 @@ private:
bool m_combineSamples;
bool m_identifySamples = false;
bool m_inconsistentSamples;
std::atomic<int64_t> m_excessiveZoneDepthTime { -1 };
bool m_allowStringModification = false;
short_ptr<GpuCtxData> m_gpuCtxMap[256];