testing on ../../test/test_patm.py
python: Python/compile.c:4420: int assemble_lnotab(struct assembler *,
struct instr *): Assertion `d_lineno >= 0' failed.
Aborted
When running my test programs I got an error as given above. Finally I found it was just quite few differences between the source codes of Python3.5 and Python3.6. Just one line:
Python3.5
static int
assemble_lnotab(struct assembler *a, struct instr *i)
{
int d_bytecode, d_lineno;
Py_ssize_t len;
unsigned char *lnotab;
d_bytecode = a->a_offset - a->a_lineno_off;
d_lineno = i->i_lineno - a->a_lineno;
assert(d_bytecode >= 0);
assert(d_lineno >= 0); // the only difference
if(d_bytecode == 0 && d_lineno == 0)
return 1;
...
Python 3.6
static int
assemble_lnotab(struct assembler *a, struct instr *i)
{
int d_bytecode, d_lineno;
Py_ssize_t len;
unsigned char *lnotab;
d_bytecode = (a->a_offset - a->a_lineno_off) * sizeof(_Py_CODEUNIT);
d_lineno = i->i_lineno - a->a_lineno;
assert(d_bytecode >= 0);
if(d_bytecode == 0 && d_lineno == 0)
return 1;
What if I just deleted assert(d_lineno >= 0);
?
You're using a debug build of 3.5. In Python 3.5 and any previous version, the line numbering within a single bytecode block (i.e. the bytecode of a module, or a function) had to be monotonic, that is each opcode had to map to a line in source code whose linenumber must be greater than or equal to the line number of the previous opcode. This was ever checked in debug builds; in release builds of Python the assert
would not be compiled in, but the generated line number tab would have been invalid anyway.
This was discussed in Issue 26107 on bugs.python.org. The requirement of monotonicity of line numbers was seen detrimental to optimizations, many of which would reorganize the generated bytecode around. Thus the check was removed in 3.6 along with other changes that make the line number delta be a signed integer.
You can comment out this assert pretty safely, as release builds would have eliminated it anyhow, but don't expect debugging to work correctly in the generated code as the line number tab is now invalid.
As an alternative, if you're reorganizing lines in the AST, or something similar, you can set all line numbers to 0 - not just the missing ones; or you can generate fake line numbers that don't break the monotonicity rule.
A coincidental problem occurred with generated ASTs, as the ast.fix_missing_locations
would write the line number of 0 to any nodes that lacked line numbering. If parts of the AST contain line numbers because they originated from ast.parse
, it will be likely that the resulting AST tree would break the monotonicity requirement - which again would only lead to problems on non-release builds of Pythons < 3.6.
The other change, that is not relevant to the bug here, is the change from bytecode to wordcode, which also was introduced in Python 3.6. Here each opcode would be a 16-bit word instead of a 8-bit byte with possible extended args. That's the reason for the offset being multiplied by sizeof(_Py_CODEUNIT);
.