@@ -2335,105 +2335,78 @@ 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 try-catch add a CATCH-PUSH instruction
2341
+ // Each CATCH-PUSH records a list of all the handler labels together with a
2342
+ // list of all the exception ids
2343
+
2344
+ // Gather all try-catch blocks that have cur_pc as the starting pc
2345
+ typedef std::vector<std::reference_wrapper<
2346
+ const java_bytecode_convert_methodt::methodt::exceptiont>> exceptionst;
2347
+ std::map<std::size_t , exceptionst> exceptions_by_end;
2348
+ for (const java_bytecode_convert_methodt::methodt::exceptiont &exception
2349
+ : method.exception_table )
2351
2350
{
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 ();
2351
+ if (exception.start_pc == cur_pc)
2352
+ exceptions_by_end[exception.end_pc ].push_back (exception);
2353
+ }
2354
+ for (const auto &exceptions : exceptions_by_end)
2355
+ {
2356
+ code_push_catcht catch_push;
2357
+ code_push_catcht::exception_listt &exception_list =
2358
+ catch_push.exception_list ();
2359
+ for (const java_bytecode_convert_methodt::methodt::exceptiont &exception
2360
+ : exceptions.second )
2361
+ {
2362
+ exception_list.emplace_back (
2363
+ exception.catch_type .get_identifier (),
2364
+ // Record the exception handler in the CATCH-PUSH instruction by
2365
+ // generating a label corresponding to the handler's pc
2366
+ label (std::to_string (exception.handler_pc )));
2367
+ }
2368
+ // Prepend the CATCH-PUSH instruction
2369
+ code = code_blockt ({ catch_push, code });
2406
2370
}
2407
2371
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
2372
+ // Next add the CATCH-POP instructions
2373
+ // exception_row.end_pc is exclusive so append CATCH-POP instructions if this
2374
+ // is the instruction before it.
2375
+ // Dangerously, we assume that the lexically next bit of code after the try
2376
+ // block (the catch block) is:
2377
+ // a) the next code in the bytecode and therefore its start address matches
2378
+ // the exclusive end position of the try block (probably a valid assumption
2379
+ // for non-obfuscated bytecode generated by most compilers)
2380
+ // b) the successor of a previous instruction and therefore in the working
2381
+ // set (not a valid assumption when there aren't any throwing statements in
2382
+ // the try block)
2383
+ // We are therefore going to find all exception handlers that end at our
2384
+ // earliest successor
2385
+ if (working_set.empty ())
2386
+ {
2387
+ // There was no throw in the try block
2388
+ // TODO: This will result in non-balanced PUSH and POPs
2389
+ return code;
2390
+ }
2391
+ const method_offsett &working_set_elt = *working_set.begin ();
2392
+ if (cur_pc >= working_set_elt)
2393
+ {
2394
+ // This just fails if we have a back-edge here
2395
+ // TODO: This will result in non-balanced PUSH and POPs
2396
+ return code;
2397
+ }
2398
+ // Count the distinct handler start positions that end at this location
2399
+ std::set<std::size_t > start_positions;
2414
2400
for (const auto &exception_row : method.exception_table )
2415
2401
{
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 )
2420
- {
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
- }
2434
- }
2402
+ // Check if working_set_elt is the end of a try block
2403
+ if (working_set_elt == exception_row.end_pc )
2404
+ start_positions.insert (exception_row.start_pc );
2435
2405
}
2436
- return c;
2406
+ for (std::size_t handler = 0 ; handler < start_positions.size (); ++handler)
2407
+ // Append a CATCH-POP instruction before the end of the try block
2408
+ code = code_blockt ({ code, code_pop_catcht () });
2409
+ return code;
2437
2410
}
2438
2411
2439
2412
code_blockt java_bytecode_convert_methodt::convert_multianewarray (
0 commit comments