fix: iteration block hook injection
We fix an issue with the instrumentation of the beginning of iteration blocks (e.g. for loops) whereby instrumenting the end might cause unexpected behaviour when the modified function is invoked. This is due to the bytecode VM not liking any bytecode interposed before the instruction that ends the iteration block (e.g. END_FOR). This also solves the problem of double-calls of the instrumented hook when hitting the beginning of such blocks.
Checklist
- [x] PR author has checked that all the criteria below are met
- The PR description includes an overview of the change
- The PR description articulates the motivation for the change
- The change includes tests OR the PR description describes a testing strategy
- The PR description notes risks associated with the change, if any
- Newly-added code is easy to change
- The change follows the library release note guidelines
- The change includes or references documentation updates if necessary
- Backport labels are set (if applicable)
Reviewer Checklist
- [x] Reviewer has checked that all the criteria below are met
- Title is accurate
- All changes are related to the pull request's stated goal
- Avoids breaking API changes
- Testing strategy adequately addresses listed risks
- Newly-added code is easy to change
- Release note makes sense to a user of the library
- If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment
- Backport labels are set in a manner that is consistent with the release branch maintenance policy
CODEOWNERS have been resolved as:
releasenotes/notes/fix-iteration-block-injection-af354b7004554dfd.yaml @DataDog/apm-python
ddtrace/internal/bytecode_injection/__init__.py @DataDog/apm-core-python
tests/internal/bytecode_injection/test_injection.py @DataDog/apm-core-python
Bootstrap import analysis
Comparison of import times between this PR and base.
Summary
The average import time from this PR is: 279 ± 5 ms.
The average import time from base is: 284 ± 8 ms.
The import time difference between this PR and base is: -5.3 ± 0.3 ms.
Import time breakdown
The following import paths have shrunk:
ddtrace.auto
2.263 ms
(0.81%)
ddtrace.bootstrap.sitecustomize
1.579 ms
(0.57%)
ddtrace.bootstrap.preload
1.579 ms
(0.57%)
ddtrace.internal.remoteconfig.client
0.705 ms
(0.25%)
ddtrace
0.685 ms
(0.25%)
ddtrace.internal._unpatched
0.035 ms
(0.01%)
json
0.035 ms
(0.01%)
json.decoder
0.035 ms
(0.01%)
re
0.035 ms
(0.01%)
enum
0.035 ms
(0.01%)
types
0.035 ms
(0.01%)
This LGTM - but it might be a good idea to find a OSS project that we can add to the exploration tests that would've caught it. My logic being, if we can find a reasonably complex project that reproduces this bug, it might container other small nuances that we haven't found in the wild yet. I opened an issue to track this here: https://datadoghq.atlassian.net/browse/DEBUG-4105
Benchmarks
Benchmark execution time: 2025-06-27 09:02:39
Comparing candidate commit 55f81bdbb4d5b23c32dc19b72075634c82935b36 in PR branch fix/iteration-block-injection with baseline commit 5fdd9c23c8f9886d201335b8b2ac141fc95bc517 in branch main.
Found 0 performance improvements and 0 performance regressions! Performance is the same for 569 metrics, 3 unstable metrics.