Skip to content

Commit c650559

Browse files
committed
fix: incorrect error message in ASTree::BuildFromCode(...)
* `opcode` was incorrectly clamped causing misleading output. * modified output with additional info about offending bytecode and position so end-user submissions can become more informative. * for `EXTENDED_ARG` bytecode the position will be off by a few bytes, but, at least the bytecode printed will be correct.
1 parent dc6ca4a commit c650559

File tree

3 files changed

+23
-11
lines changed

3 files changed

+23
-11
lines changed

ASTree.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
8585
PycRef<ASTBlock> curblock = defblock;
8686
blocks.push(defblock);
8787

88+
unsigned char bytecode;
8889
int opcode, operand;
8990
int curpos = 0;
9091
int pos = 0;
@@ -108,7 +109,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
108109
#endif
109110

110111
curpos = pos;
111-
bc_next(source, mod, opcode, operand, pos);
112+
bc_next(source, mod, bytecode, opcode, operand, pos);
112113

113114
if (need_try && opcode != Pyc::SETUP_EXCEPT_A) {
114115
need_try = false;
@@ -1788,7 +1789,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
17881789
curblock = blocks.top();
17891790
curblock->append(prev.cast<ASTNode>());
17901791

1791-
bc_next(source, mod, opcode, operand, pos);
1792+
bc_next(source, mod, bytecode, opcode, operand, pos);
17921793
}
17931794
}
17941795
break;
@@ -1811,7 +1812,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
18111812
curblock = blocks.top();
18121813
curblock->append(prev.cast<ASTNode>());
18131814

1814-
bc_next(source, mod, opcode, operand, pos);
1815+
bc_next(source, mod, bytecode, opcode, operand, pos);
18151816
}
18161817
}
18171818
break;
@@ -2474,7 +2475,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
24742475
}
24752476
break;
24762477
default:
2477-
fprintf(stderr, "Unsupported opcode: %s\n", Pyc::OpcodeName(opcode & 0xFF));
2478+
fprintf(stderr, "Unsupported opcode: %s (bytecode=%02Xh) at position %d.\n", Pyc::OpcodeName(opcode), bytecode, curpos);
24782479
cleanBuild = false;
24792480
return new ASTNodeList(defblock->nodes());
24802481
}

bytecode.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,14 +276,16 @@ void print_const(std::ostream& pyc_output, PycRef<PycObject> obj, PycModule* mod
276276
}
277277
}
278278

279-
void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& pos)
279+
void bc_next(PycBuffer& source, PycModule* mod, unsigned char& bytecode, int& opcode, int& operand, int& pos)
280280
{
281-
opcode = Pyc::ByteToOpcode(mod->majorVer(), mod->minorVer(), source.getByte());
281+
bytecode = source.getByte();
282+
opcode = Pyc::ByteToOpcode(mod->majorVer(), mod->minorVer(), bytecode);
282283
if (mod->verCompare(3, 6) >= 0) {
283284
operand = source.getByte();
284285
pos += 2;
285286
if (opcode == Pyc::EXTENDED_ARG_A) {
286-
opcode = Pyc::ByteToOpcode(mod->majorVer(), mod->minorVer(), source.getByte());
287+
bytecode = source.getByte();
288+
opcode = Pyc::ByteToOpcode(mod->majorVer(), mod->minorVer(), bytecode);
287289
operand = (operand << 8) | source.getByte();
288290
pos += 2;
289291
}
@@ -292,7 +294,8 @@ void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int&
292294
pos += 1;
293295
if (opcode == Pyc::EXTENDED_ARG_A) {
294296
operand = source.get16() << 16;
295-
opcode = Pyc::ByteToOpcode(mod->majorVer(), mod->minorVer(), source.getByte());
297+
bytecode = source.getByte();
298+
opcode = Pyc::ByteToOpcode(mod->majorVer(), mod->minorVer(), bytecode);
296299
pos += 3;
297300
}
298301
if (opcode >= Pyc::PYC_HAVE_ARG) {
@@ -340,17 +343,25 @@ void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
340343

341344
PycBuffer source(code->code()->value(), code->code()->length());
342345

346+
unsigned char bytecode;
343347
int opcode, operand;
344348
int pos = 0;
345349
while (!source.atEof()) {
346350
int start_pos = pos;
347-
bc_next(source, mod, opcode, operand, pos);
351+
bc_next(source, mod, bytecode, opcode, operand, pos);
348352
if (opcode == Pyc::CACHE && (flags & Pyc::DISASM_SHOW_CACHES) == 0)
349353
continue;
350354

351355
for (int i=0; i<indent; i++)
352356
pyc_output << " ";
353-
formatted_print(pyc_output, "%-7d %-30s ", start_pos, Pyc::OpcodeName(opcode));
357+
358+
auto opcode_name = Pyc::OpcodeName(opcode);
359+
if (opcode == Pyc::Opcode::PYC_INVALID_OPCODE) {
360+
// attempt to generate a more informative output for anyone doing copy-pasta Issue creation
361+
formatted_print(pyc_output, "%-7d %-30s (bytecode=%02Xh)", start_pos, opcode_name, bytecode);
362+
} else {
363+
formatted_print(pyc_output, "%-7d %-30s ", start_pos, opcode_name);
364+
}
354365

355366
if (opcode >= Pyc::PYC_HAVE_ARG) {
356367
switch (opcode) {

bytecode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ int ByteToOpcode(int maj, int min, int opcode);
2929

3030
void print_const(std::ostream& pyc_output, PycRef<PycObject> obj, PycModule* mod,
3131
const char* parent_f_string_quote = nullptr);
32-
void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& pos);
32+
void bc_next(PycBuffer& source, PycModule* mod, unsigned char& bytecode, int& opcode, int& operand, int& pos);
3333
void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
3434
int indent, unsigned flags);

0 commit comments

Comments
 (0)