Skip to content

Commit 2f0ddaf

Browse files
committed
Add 3.14 regression tests for line numbers and incomplete frames
Three sections in FibonacciTest guarding behavior validated against a real Python 3.14 dump: - isIncomplete() returns false for every captured (complete) frame. - currentLineNumber does not silently fall back to firstLineNumber (the c5c2880 regression that reported every frame's def line on 3.14+). - bytecodeStartAddress returns a full 64-bit address inside the code object, not a 32-bit-truncated value. No production code changes: master already carries the line-number and incomplete-frame fixes these tests exercise.
1 parent 00b52db commit 2f0ddaf

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

test/PyExtTest/FibonacciTest.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ using namespace PyExt::Remote;
1717
#include <algorithm>
1818
#include <iterator>
1919
#include <regex>
20+
#include <ios>
2021

2122
TEST_CASE("fibonacci_test.py has the expected line numbers.", "[integration][fibonacci_test]")
2223
{
@@ -85,4 +86,48 @@ TEST_CASE("fibonacci_test.py has the expected line numbers.", "[integration][fib
8586
REQUIRE((interpFramesChecked == 0 || interpFramesChecked == frames.size()));
8687
}
8788

89+
// Python 3.11 changed the co_linetable encoding, which broke our line-number lookup until it was reworked.
90+
// Now that the functionality is restored, this test prevents regressions in line number support.
91+
SECTION("currentLineNumber does not silently fall back to firstLineNumber.")
92+
{
93+
auto fibFrame = std::find_if(begin(frames), end(frames), [](auto frame) {
94+
auto c = frame->code();
95+
return c != nullptr && c->name() == "recursive_fib";
96+
});
97+
REQUIRE(fibFrame != frames.end());
98+
99+
auto code = (*fibFrame)->code();
100+
REQUIRE(code != nullptr);
101+
102+
auto currentLine = (*fibFrame)->currentLineNumber();
103+
auto firstLine = code->firstLineNumber();
104+
105+
INFO("currentLineNumber=" << currentLine << ", firstLineNumber=" << firstLine);
106+
REQUIRE(currentLine != firstLine);
107+
REQUIRE(currentLine > firstLine);
108+
}
109+
110+
// Similar regression guard for the bytecodeStartAddress().
111+
SECTION("bytecodeStartAddress returns a full 64-bit address.")
112+
{
113+
auto fibFrame = std::find_if(begin(frames), end(frames), [](auto frame) {
114+
auto c = frame->code();
115+
return c != nullptr && c->name() == "recursive_fib";
116+
});
117+
REQUIRE(fibFrame != frames.end());
118+
119+
auto code = (*fibFrame)->code();
120+
REQUIRE(code != nullptr);
121+
122+
auto start = code->bytecodeStartAddress();
123+
if (start.has_value()) {
124+
// The bytecode must live inside the PyCodeObject, so its address is strictly greater than the code object's own address.
125+
INFO("bytecodeStartAddress=0x" << std::hex << *start << ", code offset=0x" << std::hex << code->offset());
126+
REQUIRE(*start > code->offset());
127+
} else {
128+
// Python <= 3.10: no co_code_adaptive.
129+
// The old lineNumberFromInstructionOffset() path drives line numbers instead.
130+
SUCCEED("Skipping: bytecodeStartAddress not supported on this Python version.");
131+
}
132+
}
88133
}

0 commit comments

Comments
 (0)