Mercurial > hg > truffle
comparison src/share/vm/classfile/verifier.cpp @ 20328:92baebeb744b
8050485: super() in a try block in a ctor causes VerifyError
Summary: Parse catch clause paths to ensure they end in throws
Reviewed-by: dlong, acorn, kamg, ctornqvi, lfoltan
author | hseigel |
---|---|
date | Tue, 12 Aug 2014 20:29:25 -0400 |
parents | d14a18794c90 |
children | 8cb56c8cb30d |
comparison
equal
deleted
inserted
replaced
20327:411e30e5fbb8 | 20328:92baebeb744b |
---|---|
2229 } | 2229 } |
2230 default: ShouldNotReachHere(); | 2230 default: ShouldNotReachHere(); |
2231 } | 2231 } |
2232 } | 2232 } |
2233 | 2233 |
2234 // Look at the method's handlers. If the bci is in the handler's try block | |
2235 // then check if the handler_pc is already on the stack. If not, push it. | |
2236 void ClassVerifier::push_handlers(ExceptionTable* exhandlers, | |
2237 GrowableArray<u4>* handler_stack, | |
2238 u4 bci) { | |
2239 int exlength = exhandlers->length(); | |
2240 for(int x = 0; x < exlength; x++) { | |
2241 if (bci >= exhandlers->start_pc(x) && bci < exhandlers->end_pc(x)) { | |
2242 handler_stack->append_if_missing(exhandlers->handler_pc(x)); | |
2243 } | |
2244 } | |
2245 } | |
2246 | |
2247 // Return TRUE if all code paths starting with start_bc_offset end in | |
2248 // bytecode athrow or loop. | |
2249 bool ClassVerifier::ends_in_athrow(u4 start_bc_offset) { | |
2250 ResourceMark rm; | |
2251 // Create bytecode stream. | |
2252 RawBytecodeStream bcs(method()); | |
2253 u4 code_length = method()->code_size(); | |
2254 bcs.set_start(start_bc_offset); | |
2255 u4 target; | |
2256 // Create stack for storing bytecode start offsets for if* and *switch. | |
2257 GrowableArray<u4>* bci_stack = new GrowableArray<u4>(30); | |
2258 // Create stack for handlers for try blocks containing this handler. | |
2259 GrowableArray<u4>* handler_stack = new GrowableArray<u4>(30); | |
2260 // Create list of visited branch opcodes (goto* and if*). | |
2261 GrowableArray<u4>* visited_branches = new GrowableArray<u4>(30); | |
2262 ExceptionTable exhandlers(_method()); | |
2263 | |
2264 while (true) { | |
2265 if (bcs.is_last_bytecode()) { | |
2266 // if no more starting offsets to parse or if at the end of the | |
2267 // method then return false. | |
2268 if ((bci_stack->is_empty()) || ((u4)bcs.end_bci() == code_length)) | |
2269 return false; | |
2270 // Pop a bytecode starting offset and scan from there. | |
2271 bcs.set_start(bci_stack->pop()); | |
2272 } | |
2273 Bytecodes::Code opcode = bcs.raw_next(); | |
2274 u4 bci = bcs.bci(); | |
2275 | |
2276 // If the bytecode is in a TRY block, push its handlers so they | |
2277 // will get parsed. | |
2278 push_handlers(&exhandlers, handler_stack, bci); | |
2279 | |
2280 switch (opcode) { | |
2281 case Bytecodes::_if_icmpeq: | |
2282 case Bytecodes::_if_icmpne: | |
2283 case Bytecodes::_if_icmplt: | |
2284 case Bytecodes::_if_icmpge: | |
2285 case Bytecodes::_if_icmpgt: | |
2286 case Bytecodes::_if_icmple: | |
2287 case Bytecodes::_ifeq: | |
2288 case Bytecodes::_ifne: | |
2289 case Bytecodes::_iflt: | |
2290 case Bytecodes::_ifge: | |
2291 case Bytecodes::_ifgt: | |
2292 case Bytecodes::_ifle: | |
2293 case Bytecodes::_if_acmpeq: | |
2294 case Bytecodes::_if_acmpne: | |
2295 case Bytecodes::_ifnull: | |
2296 case Bytecodes::_ifnonnull: | |
2297 target = bcs.dest(); | |
2298 if (visited_branches->contains(bci)) { | |
2299 if (bci_stack->is_empty()) return true; | |
2300 // Pop a bytecode starting offset and scan from there. | |
2301 bcs.set_start(bci_stack->pop()); | |
2302 } else { | |
2303 if (target > bci) { // forward branch | |
2304 if (target >= code_length) return false; | |
2305 // Push the branch target onto the stack. | |
2306 bci_stack->push(target); | |
2307 // then, scan bytecodes starting with next. | |
2308 bcs.set_start(bcs.next_bci()); | |
2309 } else { // backward branch | |
2310 // Push bytecode offset following backward branch onto the stack. | |
2311 bci_stack->push(bcs.next_bci()); | |
2312 // Check bytecodes starting with branch target. | |
2313 bcs.set_start(target); | |
2314 } | |
2315 // Record target so we don't branch here again. | |
2316 visited_branches->append(bci); | |
2317 } | |
2318 break; | |
2319 | |
2320 case Bytecodes::_goto: | |
2321 case Bytecodes::_goto_w: | |
2322 target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w()); | |
2323 if (visited_branches->contains(bci)) { | |
2324 if (bci_stack->is_empty()) return true; | |
2325 // Been here before, pop new starting offset from stack. | |
2326 bcs.set_start(bci_stack->pop()); | |
2327 } else { | |
2328 if (target >= code_length) return false; | |
2329 // Continue scanning from the target onward. | |
2330 bcs.set_start(target); | |
2331 // Record target so we don't branch here again. | |
2332 visited_branches->append(bci); | |
2333 } | |
2334 break; | |
2335 | |
2336 // Check that all switch alternatives end in 'athrow' bytecodes. Since it | |
2337 // is difficult to determine where each switch alternative ends, parse | |
2338 // each switch alternative until either hit a 'return', 'athrow', or reach | |
2339 // the end of the method's bytecodes. This is gross but should be okay | |
2340 // because: | |
2341 // 1. tableswitch and lookupswitch byte codes in handlers for ctor explicit | |
2342 // constructor invocations should be rare. | |
2343 // 2. if each switch alternative ends in an athrow then the parsing should be | |
2344 // short. If there is no athrow then it is bogus code, anyway. | |
2345 case Bytecodes::_lookupswitch: | |
2346 case Bytecodes::_tableswitch: | |
2347 { | |
2348 address aligned_bcp = (address) round_to((intptr_t)(bcs.bcp() + 1), jintSize); | |
2349 u4 default_offset = Bytes::get_Java_u4(aligned_bcp) + bci; | |
2350 int keys, delta; | |
2351 if (opcode == Bytecodes::_tableswitch) { | |
2352 jint low = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize); | |
2353 jint high = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize); | |
2354 // This is invalid, but let the regular bytecode verifier | |
2355 // report this because the user will get a better error message. | |
2356 if (low > high) return true; | |
2357 keys = high - low + 1; | |
2358 delta = 1; | |
2359 } else { | |
2360 keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize); | |
2361 delta = 2; | |
2362 } | |
2363 // Invalid, let the regular bytecode verifier deal with it. | |
2364 if (keys < 0) return true; | |
2365 | |
2366 // Push the offset of the next bytecode onto the stack. | |
2367 bci_stack->push(bcs.next_bci()); | |
2368 | |
2369 // Push the switch alternatives onto the stack. | |
2370 for (int i = 0; i < keys; i++) { | |
2371 u4 target = bci + (jint)Bytes::get_Java_u4(aligned_bcp+(3+i*delta)*jintSize); | |
2372 if (target > code_length) return false; | |
2373 bci_stack->push(target); | |
2374 } | |
2375 | |
2376 // Start bytecode parsing for the switch at the default alternative. | |
2377 if (default_offset > code_length) return false; | |
2378 bcs.set_start(default_offset); | |
2379 break; | |
2380 } | |
2381 | |
2382 case Bytecodes::_return: | |
2383 return false; | |
2384 | |
2385 case Bytecodes::_athrow: | |
2386 { | |
2387 if (bci_stack->is_empty()) { | |
2388 if (handler_stack->is_empty()) { | |
2389 return true; | |
2390 } else { | |
2391 // Parse the catch handlers for try blocks containing athrow. | |
2392 bcs.set_start(handler_stack->pop()); | |
2393 } | |
2394 } else { | |
2395 // Pop a bytecode offset and starting scanning from there. | |
2396 bcs.set_start(bci_stack->pop()); | |
2397 } | |
2398 } | |
2399 break; | |
2400 | |
2401 default: | |
2402 ; | |
2403 } // end switch | |
2404 } // end while loop | |
2405 | |
2406 return false; | |
2407 } | |
2408 | |
2234 void ClassVerifier::verify_invoke_init( | 2409 void ClassVerifier::verify_invoke_init( |
2235 RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, | 2410 RawBytecodeStream* bcs, u2 ref_class_index, VerificationType ref_class_type, |
2236 StackMapFrame* current_frame, u4 code_length, bool *this_uninit, | 2411 StackMapFrame* current_frame, u4 code_length, bool *this_uninit, |
2237 constantPoolHandle cp, TRAPS) { | 2412 constantPoolHandle cp, TRAPS) { |
2238 u2 bci = bcs->bci(); | 2413 u2 bci = bcs->bci(); |
2248 TypeOrigin::implicit(current_type())), | 2423 TypeOrigin::implicit(current_type())), |
2249 "Bad <init> method call"); | 2424 "Bad <init> method call"); |
2250 return; | 2425 return; |
2251 } | 2426 } |
2252 | 2427 |
2253 // Make sure that this call is not done from within a TRY block because | 2428 // Check if this call is done from inside of a TRY block. If so, make |
2254 // that can result in returning an incomplete object. Simply checking | 2429 // sure that all catch clause paths end in a throw. Otherwise, this |
2255 // (bci >= start_pc) also ensures that this call is not done after a TRY | 2430 // can result in returning an incomplete object. |
2256 // block. That is also illegal because this call must be the first Java | |
2257 // statement in the constructor. | |
2258 ExceptionTable exhandlers(_method()); | 2431 ExceptionTable exhandlers(_method()); |
2259 int exlength = exhandlers.length(); | 2432 int exlength = exhandlers.length(); |
2260 for(int i = 0; i < exlength; i++) { | 2433 for(int i = 0; i < exlength; i++) { |
2261 if (bci >= exhandlers.start_pc(i)) { | 2434 u2 start_pc = exhandlers.start_pc(i); |
2262 verify_error(ErrorContext::bad_code(bci), | 2435 u2 end_pc = exhandlers.end_pc(i); |
2263 "Bad <init> method call from after the start of a try block"); | 2436 |
2264 return; | 2437 if (bci >= start_pc && bci < end_pc) { |
2438 if (!ends_in_athrow(exhandlers.handler_pc(i))) { | |
2439 verify_error(ErrorContext::bad_code(bci), | |
2440 "Bad <init> method call from after the start of a try block"); | |
2441 return; | |
2442 } else if (VerboseVerification) { | |
2443 ResourceMark rm; | |
2444 tty->print_cr( | |
2445 "Survived call to ends_in_athrow(): %s", | |
2446 current_class()->name()->as_C_string()); | |
2447 } | |
2265 } | 2448 } |
2266 } | 2449 } |
2267 | 2450 |
2268 current_frame->initialize_object(type, current_type()); | 2451 current_frame->initialize_object(type, current_type()); |
2269 *this_uninit = true; | 2452 *this_uninit = true; |