Fix: Prevent infinite loop from circular extends in config
Summary
Fixes #5096 - Resolves infinite loop when a config section extends itself (directly or indirectly).
Problem
Previously, the walk_options method in platformio/project/config.py did not check for circular dependencies when processing extends directives. This caused infinite loops in cases like:
[base]
extends = base
or more complex chains:
[common]
extends = base
[base]
extends = common
Solution
Added cycle detection by checking if a section is already in extends_done or extends_queue before adding it to the processing queue. This prevents sections from being processed multiple times and breaks circular dependency chains.
Changes
- Modified
walk_optionsmethod inplatformio/project/config.py(lines 180-188) - Changed from
extends_queue.extend()to iterating and checking each section individually - Added check:
if ext_section not in extends_done and ext_section not in extends_queue
Testing
Tested with both simple and complex circular reference cases:
- Simple circular:
[base] extends = base - Complex circular:
[common] extends = base+[base] extends = common
Both cases now complete successfully without hanging, while still preserving valid config inheritance behavior.
🤖 Generated with Claude Code