@@ -2335,105 +2335,91 @@ codet &java_bytecode_convert_methodt::do_exception_handling(
2335
2335
const java_bytecode_convert_methodt::methodt &method,
2336
2336
const std::set<method_offsett> &working_set,
2337
2337
method_offsett cur_pc,
2338
- codet &c )
2338
+ codet &code )
2339
2339
{
2340
- std::vector<irep_idt> exception_ids;
2341
- std::vector<irep_idt> handler_labels;
2342
-
2343
- // for each try-catch add a CATCH-PUSH instruction
2344
- // each CATCH-PUSH records a list of all the handler labels
2345
- // together with a list of all the exception ids
2346
-
2347
- // be aware of different try-catch blocks with the same starting pc
2348
- method_offsett pos = 0 ;
2349
- method_offsett end_pc = 0 ;
2350
- while (pos < method.exception_table .size ())
2340
+ // For each exception handler range that starts here add a CATCH-PUSH marker
2341
+ // Each CATCH-PUSH records a list of all the exception id and handler label
2342
+ // pairs handled for its exact block
2343
+
2344
+ std::vector<codet> result; // The instructions to replace code with
2345
+
2346
+ // Gather all try-catch blocks that have cur_pc as the starting pc
2347
+ typedef std::vector<std::reference_wrapper<
2348
+ const java_bytecode_convert_methodt::methodt::exceptiont>> exceptionst;
2349
+ std::map<std::size_t , exceptionst> exceptions_by_end;
2350
+ for (const java_bytecode_convert_methodt::methodt::exceptiont &exception
2351
+ : method.exception_table )
2351
2352
{
2352
- // check if this is the beginning of a try block
2353
- for (; pos < method.exception_table .size (); ++pos)
2354
- {
2355
- // unexplored try-catch?
2356
- if (cur_pc == method.exception_table [pos].start_pc && end_pc == 0 )
2357
- {
2358
- end_pc = method.exception_table [pos].end_pc ;
2359
- }
2360
-
2361
- // currently explored try-catch?
2362
- if (
2363
- cur_pc == method.exception_table [pos].start_pc &&
2364
- method.exception_table [pos].end_pc == end_pc)
2365
- {
2366
- exception_ids.push_back (
2367
- method.exception_table [pos].catch_type .get_identifier ());
2368
- // record the exception handler in the CATCH-PUSH
2369
- // instruction by generating a label corresponding to
2370
- // the handler's pc
2371
- handler_labels.push_back (
2372
- label (std::to_string (method.exception_table [pos].handler_pc )));
2373
- }
2374
- else
2375
- break ;
2376
- }
2377
-
2378
- // add the actual PUSH-CATCH instruction
2379
- if (!exception_ids.empty ())
2380
- {
2381
- code_push_catcht catch_push;
2382
- INVARIANT (
2383
- exception_ids.size () == handler_labels.size (),
2384
- " Exception tags and handler labels should be 1-to-1" );
2385
- code_push_catcht::exception_listt &exception_list =
2386
- catch_push.exception_list ();
2387
- for (size_t i = 0 ; i < exception_ids.size (); ++i)
2388
- {
2389
- exception_list.push_back (
2390
- code_push_catcht::exception_list_entryt (
2391
- exception_ids[i], handler_labels[i]));
2392
- }
2393
-
2394
- c = code_blockt ({catch_push, c});
2395
- }
2396
- else
2397
- {
2398
- // advance
2399
- ++pos;
2400
- }
2401
-
2402
- // reset
2403
- end_pc = 0 ;
2404
- exception_ids.clear ();
2405
- handler_labels.clear ();
2353
+ if (exception.start_pc == cur_pc)
2354
+ exceptions_by_end[exception.end_pc ].push_back (exception);
2355
+ }
2356
+ // Loop over each block with a distinct end position
2357
+ for (const auto &exceptions : exceptions_by_end)
2358
+ {
2359
+ // For each block create a CATCH-PUSH
2360
+ code_push_catcht catch_push;
2361
+ // Fill in its exception_list
2362
+ code_push_catcht::exception_listt &exception_list =
2363
+ catch_push.exception_list ();
2364
+ for (const java_bytecode_convert_methodt::methodt::exceptiont &exception
2365
+ : exceptions.second )
2366
+ {
2367
+ exception_list.emplace_back (
2368
+ exception.catch_type .get_identifier (),
2369
+ // Record the exception handler in the CATCH-PUSH instruction by
2370
+ // generating a label corresponding to the handler's pc
2371
+ label (std::to_string (exception.handler_pc )));
2372
+ }
2373
+ // Prepend the CATCH-PUSH instruction
2374
+ result.push_back (std::move (catch_push));
2406
2375
}
2407
2376
2408
- // next add the CATCH-POP instructions
2409
- size_t start_pc = 0 ;
2410
- // as the first try block may have start_pc 0, we
2411
- // must track it separately
2412
- bool first_handler = false ;
2413
- // check if this is the end of a try block
2414
- for (const auto &exception_row : method.exception_table )
2377
+ // Move code to result - we'll move it back later if we don't need to create
2378
+ // a new block
2379
+ result.push_back (std::move (code));
2380
+
2381
+ // Next add the CATCH-POP instructions
2382
+ // exception_row.end_pc is exclusive so append a CATCH-POP instruction if
2383
+ // this is the instruction before it.
2384
+ // To do this, attempt to find all exception handlers that end at the
2385
+ // earliest known instruction after this one.
2386
+
2387
+ // Dangerously, we assume that the next opcode in the bytecode after the end
2388
+ // of the exception handler block (whose address matches the exclusive end
2389
+ // position of the block) will be a successor of some code investigated
2390
+ // before the instruction at the end of that handler and therefore in the
2391
+ // working set.
2392
+ // As an example of where this may fail, for non-obfuscated bytecode
2393
+ // generated by most compilers the next opcode after the block ending at the
2394
+ // end of the try block is the lexically next bit of code after the try
2395
+ // block, i.e. the catch block. When there aren't any throwing statements in
2396
+ // the try block this block will not be the successor of any instruction.
2397
+
2398
+ auto next_opcode_it = std::find_if (
2399
+ working_set.begin (),
2400
+ working_set.end (),
2401
+ [cur_pc](method_offsett offset) { return offset > cur_pc; });
2402
+ if (next_opcode_it != working_set.end ())
2415
2403
{
2416
- // add the CATCH-POP before the end of the try block
2417
- if (
2418
- cur_pc < exception_row.end_pc && !working_set.empty () &&
2419
- *working_set.begin () == exception_row.end_pc )
2404
+ // Count the distinct handler start positions that end at this location
2405
+ std::set<std::size_t > start_positions; // Use a set to deduplicate
2406
+ for (const auto &exception_row : method.exception_table )
2420
2407
{
2421
- // have we already added a CATCH-POP for the current try-catch?
2422
- // (each row corresponds to a handler)
2423
- if (exception_row.start_pc != start_pc || !first_handler)
2424
- {
2425
- if (!first_handler)
2426
- first_handler = true ;
2427
- // remember the beginning of the try-catch so that we don't add
2428
- // another CATCH-POP for the same try-catch
2429
- start_pc = exception_row.start_pc ;
2430
- // add CATCH_POP instruction
2431
- code_pop_catcht catch_pop;
2432
- c = code_blockt ({c, catch_pop});
2433
- }
2408
+ // Check if the next instruction found is the (exclusive) end of a try block
2409
+ if (*next_opcode_it == exception_row.end_pc )
2410
+ start_positions.insert (exception_row.start_pc );
2434
2411
}
2412
+ for (std::size_t handler = 0 ; handler < start_positions.size (); ++handler)
2413
+ // Append a CATCH-POP instruction before the end of the block
2414
+ result.push_back (code_pop_catcht ());
2435
2415
}
2436
- return c;
2416
+
2417
+ if (result.size () != 1 )
2418
+ code = code_blockt (std::move (result));
2419
+ else
2420
+ // Move original codet back to code
2421
+ code = std::move (result[0 ]);
2422
+ return code;
2437
2423
}
2438
2424
2439
2425
code_blockt java_bytecode_convert_methodt::convert_multianewarray (
0 commit comments