Index: build/custom/msvc_2003/vmcore/vmcore.vcproj =================================================================== --- build/custom/msvc_2003/vmcore/vmcore.vcproj (revision 501374) +++ build/custom/msvc_2003/vmcore/vmcore.vcproj (working copy) @@ -994,6 +994,12 @@ RelativePath="..\..\..\..\vm\vmcore\src\verifier\ver_real.h"> + + + + m_node[count]; } // vf_Graph::GetNode -/** - * Creates a new node and sets data to it. - */ -void -vf_Graph::NewNode( unsigned begin, // begin code instruction of node - unsigned end, // end code instruction of node - unsigned len) // bytecode length of node +vf_Node_t* +vf_Graph::NewNode( vf_NodeType_t type ) { // get node assert( m_nodes ); @@ -163,34 +147,32 @@ // set node vf_Node_t* node = &nodes->m_node[count]; - node->m_start = begin; - node->m_end = end; - node->m_len = len; // increment nodes count m_nodenum++; nodes->m_used++; assert( nodes->m_used <= nodes->m_max ); - return; + node->m_type = type; + return node; } // vf_Graph::NewNode /** - * Function set data to graph node. + * Gets a bytecode length for this code range node. */ -void -vf_Graph::SetNode( unsigned num, // graph node number - unsigned begin, // begin code instruction of node - unsigned end, // end code instruction of node - unsigned len) // bytecode length of node +unsigned vf_Graph::GetNodeBytecodeLen(ContextHandle context, + NodeHandle node) { - vf_Node_t* node = GetNode( num ); - node->m_start = begin; - node->m_end = end; - node->m_len = len; - return; -} // vf_Graph::SetNode + assert(VF_TYPE_NODE_CODE_RANGE == node->m_type); + unsigned char* code_end = (node->m_end + 1 == context->m_codeNum) ? + method_get_bytecode(context->m_method) + + method_get_code_length(context->m_method) : + context->m_code[node->m_end + 1].m_addr; + unsigned len = code_end - context->m_code[node->m_start].m_addr; + return len; +} // vf_Graph::GetNodeBytecodeLen + /** * Gets graph edge. */ @@ -255,40 +237,8 @@ return; } // vf_Graph::NewEdge -/** - * Function receive first code instruction of graph node. - */ -unsigned -vf_Graph::GetNodeFirstInstr( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_start; -} // vf_Graph::GetNodeFirstInstr /** - * Function receive last code instruction of graph node. - */ -unsigned -vf_Graph::GetNodeLastInstr( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_end; -} // vf_Graph::GetNodeLastInstr - -/** - * Function receive bytecode length of graph node instructions. - */ -inline unsigned -vf_Graph::GetNodeByteCodeLen( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_len; -} // vf_Graph::GetNodeByteCodeLen - -/** * Function receive stack modifier of graph. */ int @@ -304,22 +254,14 @@ */ inline void vf_Graph::SetNodeStackModifier( unsigned num, // graph node number - int stack) // stack deep modifier + int stack) // stack depth modifier { // check node number is in range. assert( num < m_nodenum ); - GetNode( num )->m_stack = stack; + GetNode(num)->m_stack = stack; return; } // vf_Graph::SetNodeStackModifier -/** - * Function returns number of graph nodes. - */ -unsigned -vf_Graph::GetNodeNumber() -{ - return m_nodenum; -} // vf_Graph::GetNodeNumber /** * Function marks graph node. @@ -399,27 +341,6 @@ } // vf_Graph::GetNodeInitFlag /** - * Function receives IN data flow vector of node. - */ -vf_MapVector_t * -vf_Graph::GetNodeInVector( unsigned node_num ) // graph node number -{ - assert( node_num < m_nodenum ); - return &(GetNode( node_num )->m_invector); -} // vf_Graph::GetNodeInVector - -/** - * Function receives OUT data flow vector of node. - */ -vf_MapVector_t * -vf_Graph::GetNodeOutVector( unsigned node_num ) // graph node number -{ - assert( node_num <= m_nodenum ); - return &(GetNode( node_num )->m_outvector); -} // vf_Graph::GetNodeOutVector - - -/** * Function creates IN data flow vector of node. */ void @@ -441,7 +362,7 @@ if( example->m_maxstack ) { vector->m_stack = (vf_MapEntry_t*)AllocMemory( example->m_maxstack * sizeof(vf_MapEntry_t) ); - vector->m_deep = example->m_deep; + vector->m_depth = example->m_depth; vector->m_maxstack = example->m_maxstack; } if( need_copy ) { @@ -449,7 +370,7 @@ for( index = 0; index < example->m_number; index++ ) { vector->m_local[index] = example->m_local[index]; } - for( index = 0; index < example->m_deep; index++ ) { + for( index = 0; index < example->m_depth; index++ ) { vector->m_stack[index] = example->m_stack[index]; } } @@ -478,7 +399,7 @@ if( example->m_maxstack ) { vector->m_stack = (vf_MapEntry_t*)AllocMemory( example->m_maxstack * sizeof(vf_MapEntry_t) ); - vector->m_deep = example->m_deep; + vector->m_depth = example->m_depth; vector->m_maxstack = example->m_maxstack; } if( need_copy ) { @@ -486,7 +407,7 @@ for( index = 0; index < example->m_number; index++ ) { vector->m_local[index] = example->m_local[index]; } - for( index = 0; index < example->m_deep; index++ ) { + for( index = 0; index < example->m_depth; index++ ) { vector->m_stack[index] = example->m_stack[index]; } } @@ -722,7 +643,7 @@ << method_get_name( ctex->m_method ) << method_get_descriptor( ctex->m_method ) << endl ); VERIFY_DEBUG( "-- start --" ); - for( unsigned index = 0; index < GetNodeNumber(); index++ ) { + for( unsigned index = 0; index < GetNodeCount(); index++ ) { DumpNode( index, ctex ); } #endif // _VERIFY_DEBUG @@ -750,17 +671,14 @@ } // print node - if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_START_ENTRY ) ) + if( VF_TYPE_NODE_START_ENTRY == GetNode( num )->m_type) { // start node VERIFY_DEBUG( "node[" << num << "]: " << GetNode( num )->m_start << "[-] start" ); - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_END_ENTRY ) ) + } else if( VF_TYPE_NODE_END_ENTRY == GetNode( num )->m_type) { // end node VERIFY_DEBUG( "node[" << num << "]: " << GetNode( num )->m_start << "[-] end" ); VERIFY_DEBUG( "-- end --" ); - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_HANDLER ) ) + } else if( VF_TYPE_NODE_HANDLER == GetNode( num )->m_type ) { // handler node VERIFY_DEBUG( "node[" << num << "]: " << num << "handler entry" ); } else { // another nodes @@ -903,22 +821,21 @@ vf_Context_t *ctex) // verifier contex { #if _VERIFY_DEBUG + vf_Node_t* node = GetNode( num ); + // print node to dot file - if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_START_ENTRY ) ) + if( VF_TYPE_NODE_START_ENTRY == node->m_type ) { // start node out << "node" << num << " [label=\"START\", color=limegreen]" << endl; - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_END_ENTRY ) ) + } else if( VF_TYPE_NODE_END_ENTRY == node->m_type ) { // end node out << "node" << num << " [label=\"END\", color=orangered]" << endl; - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_HANDLER ) ) + } else if( VF_TYPE_NODE_HANDLER == node->m_type ) { // handler node out << "node" << num << " [label=\"Handler #" - << num << "\\n---------\\n" << "Type: #" << GetNode( num )->m_len + << num << "\\n---------\\n" << "Type: #0" // FIXME remove type after testing << "\", shape=ellipse, color=aquamarine]" << endl; - } else { // another nodes + } else { // other nodes out << "node" << num << " [label=\""; DumpDotNodeInternal( num, "\\n---------\\n", "\\l", out, ctex ); @@ -928,20 +845,18 @@ // print node outcoming edges to dot file unsigned index; unsigned edge_num; - for( index = 0, edge_num = GetNode( num )->m_outedge; - index < GetNode( num )->m_outnum; + for( index = 0, edge_num = node->m_outedge; + index < node->m_outnum; index++ ) { vf_Edge_t *edge = GetEdge( edge_num ); out << "node" << num << " -> " << "node" << edge->m_end; - if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( edge->m_end )->m_start], - VF_FLAG_HANDLER ) ) + if( VF_TYPE_NODE_HANDLER == GetNode( edge->m_end )->m_type ) { out << "[color=red]" << endl; - } else if( num + 1 != edge->m_end // it's a subroutine call branch - && vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_end], - VF_FLAG_SUBROUTINE ) ) + } else if( ( VF_TYPE_NODE_CODE_RANGE == node->m_type ) + && vf_is_subroutine_call( ctex, edge ) ) { out << "[color=blue]" << endl; } @@ -997,134 +912,166 @@ ********************** Graph Creation ********************** ************************************************************/ + /** - * Function creates bytecode control flow graph. + * Creates bytecode control flow graph. */ Verifier_Result -vf_create_graph( vf_Context_t *ctex ) // verifier context +vf_create_graph(vf_Context_t* context) { - /** - * Create graph - */ - ctex->m_graph = new vf_Graph( ctex->m_nodeNum, ctex->m_edgeNum, ctex->m_pool ); + context->m_graph = new vf_Graph(context->m_nodeNum, + context->m_edgeNum, + context->m_pool); // use numbers pre-calculated at vf_parse_bytecode + vf_Graph_t* graph = context->m_graph; - /** - * Create decoding array: code to node - */ - unsigned* code2node = (unsigned*)vf_alloc_pool_memory( ctex->m_pool, - ctex->m_codeNum * sizeof(unsigned) ); - /** - * Create start-entry and handler nodes - */ - unsigned index; - unsigned short handlcount = method_get_exc_handler_number( ctex->m_method ); - ctex->m_graph->NewNode( 0, 0, 0 ); - for( index = 1; index < (unsigned)handlcount + 1; index++ ) { - ctex->m_graph->NewNode( index, index, 0 ); - ctex->m_graph->SetNodeStackModifier( index, 1 ); + // the array contains a corresponding node for each pc + unsigned* code2node = (unsigned*) vf_alloc_pool_memory(context->m_pool, + context->m_codeNum * sizeof(unsigned)); + + unsigned node_index; + graph->NewNode(VF_TYPE_NODE_START_ENTRY); + + // create handler nodes + unsigned short handler_count = method_get_exc_handler_number(context->m_method); + for (node_index = 1; node_index <= (unsigned) handler_count; node_index++) + { + graph->NewNode(VF_TYPE_NODE_HANDLER); + graph->SetNodeStackModifier(node_index, 1); } /** - * Create nodes - * Node count begins from the first basic block after the last handler node. - * Skip the first instruction, because we create the first node - * at his end instruction. + * Create code range nodes. New node correspond to the subsequent + * basic blocks of instructions. + * Note: code range nodes follow after the last handler node. */ - unsigned len; - unsigned last; - unsigned nodeCount; - for( last = nodeCount = 1 + handlcount, index = last + 1; - index < ctex->m_codeNum - 1; - index++ ) - { - if( vf_is_begin_basic_block( &ctex->m_code[index] ) ) { - // set graph nodes - len = ctex->m_code[index].m_addr - ctex->m_code[last].m_addr; - ctex->m_graph->NewNode( last, index - 1, len ); - ctex->m_graph->SetNodeStackModifier( nodeCount, - vf_get_node_stack_deep( &ctex->m_code[last], &ctex->m_code[index - 1] ) ); - code2node[last] = nodeCount++; - last = index; + unsigned bb_start = 0; + unsigned bytecode_len = method_get_code_length(context->m_method); + // adding a basic block which starts + for (; bb_start < context->m_codeNum; + node_index++) { + // find a basic block end + unsigned next_bb_start = bb_start + 1; + while ((next_bb_start < context->m_codeNum) + && (!context->m_code[next_bb_start].m_basic_block_start)) { + next_bb_start++; } + + graph->NewNode(bb_start, next_bb_start - 1); + graph->SetNodeStackModifier(node_index, + vf_get_node_stack_depth(&context->m_code[bb_start], + &context->m_code[next_bb_start - 1])); + code2node[bb_start] = node_index; + bb_start = next_bb_start; } - // set last node with code segment - unsigned char* code_end = method_get_bytecode( ctex->m_method ) - + method_get_code_length( ctex->m_method ); - len = code_end - ctex->m_code[last].m_addr; - ctex->m_graph->NewNode( last, index - 1, len ); - ctex->m_graph->SetNodeStackModifier( nodeCount, - vf_get_node_stack_deep( &ctex->m_code[last], &ctex->m_code[index - 1] ) ); - code2node[last] = nodeCount++; + // set exit node - ctex->m_graph->NewNode( ctex->m_codeNum - 1, 0, 0 ); - code2node[ctex->m_codeNum - 1] = nodeCount++; - assert( ctex->m_nodeNum == nodeCount ); + graph->NewNode(VF_TYPE_NODE_END_ENTRY); + unsigned node_num = node_index + 1; + assert(context->m_nodeNum == node_num); /** * Create edges - * First edge from start-entry node to first code node */ - ctex->m_graph->NewEdge( 0, handlcount + 1 ); - for( index = 1; index < nodeCount - 1; index++ ) { - vf_Code_t* codeInstr = &ctex->m_code[ ctex->m_graph->GetNodeLastInstr( index ) ]; - // check correct branching - if( codeInstr->m_addr && *codeInstr->m_addr == OPCODE_WIDE ) { - // node ends in wide instruction - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Illegal target of jump or branch" ); - return VER_ErrorBranch; - } + + // from start-entry node to the first code node + node_index = handler_count + 1; + graph->NewEdge(0, node_index); + + // create code range edges + for (; node_index < node_num - 1; node_index++) + { + vf_Code_t* code = &context->m_code[ + graph->GetNodeLastInstr(node_index)]; + // set control flow edges - if( codeInstr->m_offcount ) { - for( unsigned count = 0; count < codeInstr->m_offcount; count++ ) { -#if _VERIFY_DEBUG - if( code2node[ codeInstr->m_off[count] ] == 0 ) { - VERIFY_DEBUG( "vf_create_graph: error graph construction" ); - vf_error(); + if( code->m_offcount ) { + for( unsigned count = 0; + count < code->m_offcount; count++ ) { + int offset = vf_get_code_branch(code, count); + unsigned node = code2node[ + context->m_bc[offset].m_instr - 1]; + assert(node); + + context->m_graph->NewEdge(node_index, node); + if( node < node_index ) { + // node has a backward branch, thus any + // object on the stack should be initialized + context->m_graph->SetNodeInitFlag(node, true); } -#endif // _VERIFY_DEBUG - unsigned node = code2node[ codeInstr->m_off[count] ]; - ctex->m_graph->NewEdge( index, node ); - if( node < index ) { - // node has backward branch, - // thus the reference in local variables have to be initialized - ctex->m_graph->SetNodeInitFlag( node, true ); - } } + } else if (code->m_type) { + // FIXME compatibility issue - no need to + // have these branches + graph->NewEdge(node_index, node_num - 1); + } else if (node_index + 1 < node_num) { + graph->NewEdge(node_index, node_index + 1); } else { - if( index + 1 == nodeCount - 1 ) { - // set edge to end-entry node without return - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Falling off the end of the code" ); - return VER_ErrorBranch; - } - ctex->m_graph->NewEdge( index, index + 1 ); + VERIFY_REPORT_METHOD(context, + "Falling off the end of the code"); + return VER_ErrorBranch; } - if( codeInstr->m_handler != NULL ) { - // node is protected by exception handler, - // thus the reference in local variables have to be initialized - ctex->m_graph->SetNodeInitFlag( index, true ); - // set exception handler edges - for( unsigned count = 0; count < handlcount; count++ ) { - if( codeInstr->m_handler[count] ) { - // set edge to exception handler entry - ctex->m_graph->NewEdge( index, count + 1 ); - } + } + + unsigned char* start_bc = method_get_bytecode(context->m_method); + for (unsigned short handler_index = 0; + handler_index < handler_count; handler_index++) { + unsigned short start_pc, end_pc, handler_pc; + unsigned short handler_cp_index; + method_get_exc_handler_info(context->m_method, + handler_index, &start_pc, &end_pc, + &handler_pc, &handler_cp_index); + + vf_ValidType_t *type = NULL; + if (handler_cp_index) { + const char* name = vf_get_cp_class_name(context->m_class, + handler_cp_index); + assert(name); + + type = vf_create_class_valid_type(name, context); + // set restriction for handler class + if(context->m_vtype.m_throwable->string[0] != type->string[0]) { + context->m_type->SetRestriction( + context->m_vtype.m_throwable->string[0], + type->string[0], 0, VF_CHECK_SUPER); } } + + // create out vector for a handler + vf_MapVector_t* p_outvector = + context->m_graph->GetNodeOutVector(handler_index + 1); + + vf_new_vector(&p_outvector->m_stack, 1, context->m_pool); + p_outvector->m_depth = 1; + vf_set_vector_stack_entry_ref(p_outvector->m_stack, 0, type); + + // outcoming handler edge + graph->NewEdge(handler_index + 1, + code2node[context->m_bc[handler_pc].m_instr - 1]); + + // node range start + node_index = code2node[context->m_bc[start_pc].m_instr - 1]; + + unsigned last_node = (end_pc == bytecode_len) ? + node_num - 1 : + code2node[context->m_bc[end_pc].m_instr - 1]; + + for (; node_index < last_node; node_index++) { + // node is protected by exception handler, thus the + // reference in local variables have to be initialized + graph->SetNodeInitFlag(node_index, true); + graph->NewEdge(node_index, handler_index + 1); + } } + // one edge is reserved + assert(graph->GetEdgeCount() == context->m_edgeNum); #if _VERIFY_DEBUG - if( ctex->m_dump.m_graph ) { - ctex->m_graph->DumpGraph( ctex ); + if (context->m_dump.m_graph) { + graph->DumpGraph(context); } - if( ctex->m_dump.m_dot_graph ) { - ctex->m_graph->DumpDotGraph( ctex ); + if (context->m_dump.m_dot_graph) { + graph->DumpDotGraph(context); } #endif // _VERIFY_DEBUG @@ -1136,39 +1083,27 @@ ************************************************************/ /** - * Function evaluates stack deep of graph node. + * Function evaluates stack depth of graph code range node. */ static int -vf_get_node_stack_deep( vf_Code_t *begin, // begin code instruction of node - vf_Code_t *end) // end code instruction of node +vf_get_node_stack_depth( vf_Code_t *start, // beginning instruction + vf_Code_t *end) // ending instruction { int result = 0; vf_Code_t *pointer; - /** - * For start, end and handler nodes - */ - if( vf_is_instruction_has_flags( begin, - VF_FLAG_HANDLER | VF_FLAG_START_ENTRY | VF_FLAG_END_ENTRY ) ) - { - return 0; - } -#if _VERIFY_DEBUG - if( begin > end ) { - VERIFY_DEBUG( "vf_get_node_stack_deep: stack evaluation error" ); - vf_error(); - } -#endif // _VERIFY_DEBUG - + assert(start <= end); + /** - * Evaluate stack deep + * Evaluate stack depth */ - for( pointer = begin; pointer <= end; pointer++ ) { + for( pointer = start; pointer <= end; pointer++ ) { result += pointer->m_stack; } return result; -} // vf_get_node_stack_deep +} // vf_get_node_stack_depth + /** * Function provides some checks of control flow and data flow structures of graph. */ @@ -1188,20 +1123,20 @@ vf_Code_t *code = ctex->m_code; /** - * Check stack deep correspondence + * Check stack depth correspondence */ unsigned index = 1; - Verifier_Result result = vf_check_stack_deep( 0, VERIFY_START_MARK, + Verifier_Result result = vf_check_stack_depth( 0, VERIFY_START_MARK, maxstack + VERIFY_START_MARK, &index, ctex ); if( result != VER_OK ) { goto labelEnd_bypassGraphStructure; } - assert( index <= vGraph->GetNodeNumber() ); + assert( index <= vGraph->GetNodeCount() ); /** * Determine dead code nodes */ - index = vGraph->GetNodeNumber() - index; // number of dead code nodes + index = vGraph->GetNodeCount() - index; // number of dead code nodes /** * Override all dead nodes @@ -1209,12 +1144,13 @@ if( index ) { /** - * Identify dead code nodes and fill by nop instruction + * Identify dead code nodes and fill by nop instruction. */ - for( index = handlcount + 1; index < vGraph->GetNodeNumber() - 1; index++ ) { + for( index = handlcount + 1; index < vGraph->GetNodeCount() - 1; index++ ) { if( !vGraph->IsNodeMarked( index ) ) { unsigned char *instr = code[ vGraph->GetNodeFirstInstr( index ) ].m_addr; - for( count = 0; count < vGraph->GetNodeByteCodeLen( index ); count++ ) { + unsigned len = vGraph->GetNodeBytecodeLen(ctex, vGraph->GetNode(index)); + for(count = 0; count < len; count++) { instr[count] = OPCODE_NOP; } vGraph->SetNodeStackModifier( index, 0 ); @@ -1232,10 +1168,11 @@ #endif // _VERIFY_DEBUG /** - * Check code execution drops - * Override all incoming edges to the end-entry node + * Check that execution flow terminates with + * return or athrow bytecodes. + * Override all incoming edges to the end-entry node. */ - for( inedge = vGraph->GetNodeFirstInEdge( vGraph->GetNodeNumber() - 1 ); + for( inedge = vGraph->GetNodeFirstInEdge( vGraph->GetNodeCount() - 1 ); inedge; inedge = vGraph->GetEdgeNextInEdge( inedge ) ) { @@ -1249,10 +1186,8 @@ || !((*instr) >= OPCODE_IRETURN && (*instr) <= OPCODE_RETURN || (*instr) == OPCODE_ATHROW) ) { // illegal instruction - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Falling off the end of the code" ); + VERIFY_REPORT_METHOD( ctex, + "Falling off the end of the code" ); result = VER_ErrorCodeEnd; goto labelEnd_bypassGraphStructure; } @@ -1272,115 +1207,106 @@ * Function checks stack overflow of graph node instruction. */ static inline Verifier_Result -vf_check_node_stack_deep( unsigned nodenum, // graph node number - int deep, // initial stack deep +vf_check_node_stack_depth( unsigned nodenum, // graph node number + int depth, // initial stack depth unsigned max_stack, // maximal stack vf_Context_t *ctex) // verifier context { - /** - * Get begin and end code instruction of graph node - */ - unsigned begin = ctex->m_graph->GetNodeFirstInstr( nodenum ); - unsigned end = ctex->m_graph->GetNodeLastInstr( nodenum ); - assert( begin <= end ); - + vf_Node_t* node = ctex->m_graph->GetNode( nodenum ); /** * For start, end and handler nodes */ - if( vf_is_instruction_has_flags( &ctex->m_code[begin], - VF_FLAG_HANDLER | VF_FLAG_START_ENTRY | VF_FLAG_END_ENTRY ) ) - { + if( node->m_type != VF_TYPE_NODE_CODE_RANGE ) { return VER_OK; } + + /** + * Get begin and end code instruction of graph node + */ + unsigned start = node->m_start; + unsigned end = node->m_end; + assert( start <= end ); /** - * Evaluate stack deep + * Evaluate stack depth */ unsigned index; vf_Code_t *pointer; - int stack_deep = 0; - for( index = begin, pointer = &ctex->m_code[index]; index <= end; index++, pointer++ ) { - if( pointer->m_minstack + VERIFY_START_MARK > stack_deep + deep ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Unable to pop operand off an empty stack" ); + int stack_depth = 0; + for( index = start, pointer = &ctex->m_code[index]; index <= end; index++, pointer++ ) { + if( pointer->m_minstack + VERIFY_START_MARK > stack_depth + depth ) { + VERIFY_REPORT_METHOD( ctex, + "Unable to pop operand off an empty stack" ); return VER_ErrorStackOverflow; } - stack_deep += pointer->m_stack; - if( stack_deep + deep > (int)max_stack || stack_deep + deep < VERIFY_START_MARK ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Instruction stack overflow" ); + stack_depth += pointer->m_stack; + if( stack_depth + depth > (int)max_stack || stack_depth + depth < VERIFY_START_MARK ) { + VERIFY_REPORT( ctex, + "Instruction stack overflow" ); return VER_ErrorStackOverflow; } } #if _VERIFY_DEBUG - if( stack_deep != ctex->m_graph->GetNodeStackModifier( nodenum ) ) { - VERIFY_DEBUG( "vf_check_node_stack_deep: error stack modifier calculate" ); + if( stack_depth != ctex->m_graph->GetNodeStackModifier( nodenum ) ) { + VERIFY_DEBUG( "vf_check_node_stack_depth: error stack modifier calculate" ); vf_error(); } #endif // _VERIFY_DEBUG return VER_OK; -} // vf_check_node_stack_deep +} // vf_check_node_stack_depth /** - * Function checks graph nodes stack deep consistency. It's recursive function. + * Function checks graph nodes stack depth consistency. It's recursive function. * Function returns result of check. */ static Verifier_Result -vf_check_stack_deep( unsigned nodenum, // graph node number - int stack_deep, // initial stack deep of node +vf_check_stack_depth( unsigned nodenum, // graph node number + int stack_depth, // initial stack depth of node unsigned maxstack, // maximal stack unsigned *count, // pointer to checked node count vf_Context_t *ctex) // verifier context { - int deep; + int depth; unsigned outnode, outedge; Verifier_Result result = VER_OK; + vf_Node_t* node = ctex->m_graph->GetNode( nodenum ); + /** * Skip end-entry node */ - if( vf_is_instruction_has_flags( &ctex->m_code[ctex->m_graph->GetNodeFirstInstr( nodenum )], - VF_FLAG_END_ENTRY) ) - { + if( VF_TYPE_NODE_END_ENTRY == node->m_type ) { return VER_OK; } /** * Check handler node */ - if( vf_is_instruction_has_flags( &ctex->m_code[ctex->m_graph->GetNodeFirstInstr( nodenum )], - VF_FLAG_HANDLER) ) - { + if( VF_TYPE_NODE_HANDLER == node->m_type ) { // Reset stack for handler nodes - stack_deep = VERIFY_START_MARK; + stack_depth = VERIFY_START_MARK; } /** - * Check node stack deep + * Check node stack depth */ - deep = ctex->m_graph->GetNodeMark( nodenum ); - if( !deep ) { - // stack deep don't set, mark node by his stack deep - ctex->m_graph->SetNodeMark( nodenum, stack_deep ); + depth = ctex->m_graph->GetNodeMark( nodenum ); + if( !depth ) { + // stack depth don't set, mark node by his stack depth + ctex->m_graph->SetNodeMark( nodenum, stack_depth ); (*count)++; } else { - if( stack_deep == deep ) { - // consistent stack deep in graph + if( stack_depth == depth ) { + // consistent stack depth in graph return VER_OK; } else { - // inconsistent stack deep in graph - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Inconsistent stack deep: " - << stack_deep - VERIFY_START_MARK << " != " - << deep - VERIFY_START_MARK ); + // inconsistent stack depth in graph + VERIFY_REPORT( ctex, + "Inconsistent stack depth: " + << stack_depth - VERIFY_START_MARK << " != " + << depth - VERIFY_START_MARK ); return VER_ErrorStackDeep; } } @@ -1388,15 +1314,15 @@ /** * Check node stack overflow */ - result = vf_check_node_stack_deep( nodenum, stack_deep, maxstack, ctex ); + result = vf_check_node_stack_depth( nodenum, stack_depth, maxstack, ctex ); if( result != VER_OK ) { return result; } /** - * Override all out edges and set stack deep for out nodes + * Override all out edges and set stack depth for out nodes */ - deep = stack_deep + ctex->m_graph->GetNodeStackModifier( nodenum ); + depth = stack_depth + ctex->m_graph->GetNodeStackModifier( nodenum ); for( outedge = ctex->m_graph->GetNodeFirstOutEdge( nodenum ); outedge; outedge = ctex->m_graph->GetEdgeNextOutEdge( outedge ) ) @@ -1404,12 +1330,12 @@ // get out node outnode = ctex->m_graph->GetEdgeEndNode( outedge ); // mark out node with its out nodes - result = vf_check_stack_deep( outnode, deep, maxstack, count, ctex ); + result = vf_check_stack_depth( outnode, depth, maxstack, count, ctex ); if( result != VER_OK ) { return result; } } return result; -} // vf_check_stack_deep +} // vf_check_stack_depth } // namescape Verifier Index: vm/vmcore/src/verifier/ver_real.h =================================================================== --- vm/vmcore/src/verifier/ver_real.h (revision 504232) +++ vm/vmcore/src/verifier/ver_real.h (working copy) @@ -15,13 +15,17 @@ * limitations under the License. */ /** - * @author Pavel Rebriy + * @author Pavel Rebriy, Alexei Fedotov * @version $Revision: 1.1.2.3.4.4 $ */ #ifndef _VERIFIER_REAL_H_ #define _VERIFIER_REAL_H_ +/** + * @file + * Verifier interfaces. + */ #include #include @@ -37,7 +41,8 @@ using namespace std; /** - * Set namespace Verifier. + * @namespace Verifier + * Contains bytecode verificator. */ namespace Verifier { @@ -72,6 +77,12 @@ stream << error_message; \ vf_set_error_message( stream, (context) ); \ } +#define VERIFY_REPORT_METHOD(context, error_message ) \ + VERIFY_REPORT(context, \ + "(class: " << class_get_name( context->m_class ) \ + << ", method: " << method_get_name( context->m_method ) \ + << method_get_descriptor( context->m_method ) \ + << ") " << error_message ) /** * Define source code line and source file name parameters and arguments. @@ -271,20 +282,26 @@ } vf_MapType_t; /** - * Code instruction flags enum. + * Each instruction has a descriptive bitmap. */ typedef enum { - VF_FLAG_NONE = 0, - VF_FLAG_BEGIN_BASIC_BLOCK = 1, - VF_FLAG_START_ENTRY = 2, - VF_FLAG_END_ENTRY = 4, - VF_FLAG_HANDLER = 8, - VF_FLAG_RETURN = 16, - VF_FLAG_THROW = 32, - VF_FLAG_SUBROUTINE = 64 -} vf_InstructionFlag_t; + VF_TYPE_INSTR_NONE = 0, + VF_TYPE_INSTR_RETURN = 1, + VF_TYPE_INSTR_THROW = -2, + VF_TYPE_INSTR_SUBROUTINE = -1 +} vf_CodeType_t; /** + * Each node has a descriptive bitmap. + */ +typedef enum { + VF_TYPE_NODE_CODE_RANGE = 0, + VF_TYPE_NODE_START_ENTRY = 1, + VF_TYPE_NODE_END_ENTRY = -2, + VF_TYPE_NODE_HANDLER = -1 +} vf_NodeType_t; + +/** * Verifier structures. */ //=========================================================== @@ -293,6 +310,11 @@ */ /// Verifier context structure. typedef struct vf_Context vf_Context_t; +/** + * @ingroup Handles + * The handle of the verifier context. + */ +typedef const struct vf_Context* ContextHandle; /// Verifier code instruction structure. typedef struct vf_Code_s vf_Code_t; /// Graph node container structure @@ -303,6 +325,11 @@ typedef struct vf_Graph vf_Graph_t; /// Verifier graph node structure. typedef struct vf_Node_s vf_Node_t; +/** + * @ingroup Handles + * The handle of the graph node. + */ +typedef const struct vf_Node_s* NodeHandle; /// Verifier graph edge structure. typedef struct vf_Edge_s vf_Edge_t; /// Verifier type constraint structure. @@ -319,16 +346,15 @@ /** * Code instruction structures. */ -//=========================================================== + /** - * Initial struct of bytecode instruction. + * A byte of a bytecode. */ typedef struct { - unsigned *m_off; ///< array of branches - unsigned m_instr; ///< number of code instruction @see vf_Code_s - unsigned m_offcount : 31; ///< number of branches - unsigned m_mark : 1; ///< control flow branch flag -} vf_Instr_t; + unsigned m_instr; ///< a number + 1 of code instruction at + ///< vf_Context.m_code + unsigned m_mark : 1; ///< control flow branch flag +} vf_BCode_t; /** * Valid types structure. @@ -361,17 +387,19 @@ * Complete struct of bytecode instructions. */ struct vf_Code_s { - unsigned char *m_addr; ///< address of bytecode instruction - unsigned *m_off; ///< array of instruction branches - unsigned char *m_handler; ///< array of instruction handlers - vf_MapEntry_t *m_invector; ///< stack map IN instruction vector - vf_MapEntry_t *m_outvector; ///< stack map OUT instruction vector - unsigned m_offcount; ///< number of instruction branches - unsigned short m_minstack; ///< minimal stack for instruction - unsigned short m_inlen; ///< stack map IN instruction vector length - unsigned short m_outlen; ///< stack map OUT instruction vector length - short m_stack; ///< stack change for instruction - unsigned m_base : 7; ///< instruction flag @see vf_InstructionFlag_t + unsigned char *m_addr; ///< address of bytecode instruction + unsigned m_offcount; ///< number of instruction branches + unsigned *m_off; ///< array of instruction branches + unsigned m_sum; ///< number of basic blocks before + ///< this instruction + vf_MapEntry_t *m_invector; ///< stack map IN instruction vector + vf_MapEntry_t *m_outvector; ///< stack map OUT instruction vector + unsigned short m_minstack; ///< minimal stack for instruction + unsigned short m_inlen; ///< stack map IN instruction vector length + unsigned short m_outlen; ///< stack map OUT instruction vector length + short m_stack; ///< stack change for instruction + bool m_basic_block_start : 1; ///< begin of a basic block + vf_CodeType_t m_type : 2; ///< instruction flag @see vf_CodeType_t }; /** @@ -402,7 +430,7 @@ vf_MapEntry_t *m_stack; ///< stack map vector vf_MapEntry_t *m_local; ///< locals map vector unsigned short m_number; ///< number of locals - unsigned short m_deep; ///< stack deep + unsigned short m_depth; ///< stack depth unsigned short m_maxstack; ///< max stack length unsigned short m_maxlocal; ///< max local number } vf_MapVector_t; @@ -412,19 +440,20 @@ */ struct vf_Node_s { - vf_MapVector_t m_invector; ///< stack map IN node vector - vf_MapVector_t m_outvector; ///< stack map OUT node vector - unsigned m_start; ///< beginning of the first instruction of the BB - unsigned m_end; ///< beginning of the last instruction of the BB. - unsigned m_inedge; ///< the first of incoming node edges - unsigned m_outedge; ///< the first of outcoming node edges - unsigned m_len; ///< length of the basic block - unsigned m_innum; ///< number of incoming edges - unsigned m_outnum; ///< number of outcoming edges - unsigned m_nodecount; ///< node count in enumeration - int m_stack; ///< stack deep of node - int m_mark; ///< node mark - bool m_initialized; ///< reference in local variable should be initialized + vf_MapVector_t m_inMapVector; ///< stack map IN node vector + vf_MapVector_t m_outMapVector; ///< stack map OUT node vector + unsigned m_start; ///< index of the first instruction at vf_Context.m_code + unsigned m_end; ///< index of the last instruction at vf_Context.m_code + unsigned m_inedge; ///< the first incoming edge + unsigned m_outedge; ///< the first outcoming edge + unsigned m_innum; ///< number of incoming edges + unsigned m_outnum; ///< number of outcoming edges + unsigned m_nodecount; ///< node count in enumeration + int m_stack; ///< stack depth + int m_mark; ///< node mark + bool m_initialized : 1; ///< reference in a local variable + ///< should be initialized + vf_NodeType_t m_type : 2; ///< node type }; /** @@ -498,39 +527,47 @@ void CreateNodes( unsigned count ); /** - * Gets graph node. - * Parameter node_num must be in range. + * Gets a graph node. * - * @param[in] node_num - node number + * @param[in] node_num a node number, should be in range + * @return a handle of the node + */ + vf_Node_t* GetNode(unsigned node_num); + + /** + * Gets the first node. * - * @return The pointer to node structure. + * @return a handle of the node */ - vf_Node_t* GetNode( unsigned node_num ); + NodeHandle GetFirstNode() + { + return GetNode(0); + } /** - * Creates a new node and sets data to it. + * Creates a new node of a specific type. * Node array must have enough free space for a new element. * - * @param[in] begin_instr - begin code instruction of node - * @param[in] end_instr - end code instruction of code - * @param[in] bytecode_len - bytecode length of node instructions + * @param[in] m_type node type + * @return created node */ - void NewNode( unsigned begin_instr, - unsigned end_instr, - unsigned bytecode_len); + vf_Node_t* NewNode( vf_NodeType_t m_type ); /** - * Function set data to graph node. - * @param node_num - number of graph node - * @param begin_instr - begin code instruction of node - * @param end_instr - end code instruction of code - * @param bytecode_len - bytecode length of node instructions - * @note Assertion is raised if node_num is out of range. + * Creates a new node for a bytecode range. + * Node array must have enough free space for a new element. + * + * @param[in] start instruction start index + * @param[in] end instruction end index */ - void SetNode( unsigned node_num, - unsigned begin_instr, - unsigned end_instr, - unsigned bytecode_len ); + void NewNode(unsigned start, unsigned end) + { + // get node + vf_Node_t* node = NewNode(VF_TYPE_NODE_CODE_RANGE); + node->m_start = start; + node->m_end = end; + return; + } // NewNode(start, end, len) /** * Gets graph edge. @@ -553,28 +590,41 @@ unsigned end_node); /** - * Function receive first code instruction of graph node. - * @param node_num - graph node number - * @return Number of first code instruction of graph node. - * @note Assertion is raised if node_num is out of range. + * Gets the first code instruction of a node. + * @param node_num the node number + * @return a number of the first code instruction of graph node + * @note Assertion is raised if node_num is not a + * code range node. */ - unsigned GetNodeFirstInstr( unsigned node_num ); + unsigned GetNodeFirstInstr(unsigned node_num) { + NodeHandle node = GetNode(node_num); + assert(VF_TYPE_NODE_CODE_RANGE == node->m_type); + return node->m_start; + } // GetNodeFirstInstr /** - * Function receive last code instruction of graph node. - * @param node_num - graph node number - * @return Number of last code instruction of graph node. - * @note Assertion is raised if node_num is out of range. + * Gets the last code instruction of a node. + * @param node_num the node number + * @return a number of the last code instruction of graph node + * @note Assertion is raised if node_num is not a + * code range node. */ - unsigned GetNodeLastInstr( unsigned node_num ); + unsigned GetNodeLastInstr(unsigned node_num) { + NodeHandle node = GetNode(node_num); + assert(VF_TYPE_NODE_CODE_RANGE == node->m_type); + return node->m_end; + } // GetNodeLastInstr /** - * Function receive bytecode length of graph node instructions. - * @param node_num - graph node number - * @return Bytecode length of graph node instructions. - * @note Assertion is raised if node_num is out of range. + * Gets a bytecode length of a graph node instructions. + * @param context a verifier context handle + * @param node a node handle + * @return a number of the last code instruction of graph node + * @note Assertion is raised if node_num is not a + * code range node. */ - unsigned GetNodeByteCodeLen( unsigned node_num ); + unsigned GetNodeBytecodeLen(ContextHandle context, + NodeHandle node); /** * Function receive stack modifier of graph. @@ -593,12 +643,23 @@ void SetNodeStackModifier( unsigned node_num, int stack ); /** - * Function returns number of graph nodes. - * @return Number of graph nodes. + * Counts graph nodes. + * @return a number of graph nodes */ - unsigned GetNodeNumber(); + unsigned GetNodeCount() { + return m_nodenum; + } /** + * Counts graph edges excluding + * the reserved edge. + * @return a number of graph edges + */ + unsigned GetEdgeCount() { + return m_edgenum - 1; + } + + /** * Function marks graph node. * @param node_num - graph node number * @param mark - node mark @@ -671,24 +732,29 @@ void SetNodeOutVector( unsigned node_num, vf_MapVector_t *example, bool need_copy ); - /** - * Function receives IN data flow vector of node. - * @param node_num - graph node number - * @return IN data flow stack map vector of node. + * Gets IN data flow vector for the node. + * @param node_num graph node number + * @return a reference to IN data flow stack map vector * @note Assertion is raised if node_num is out of range. * @see vf_MapVector_t */ - vf_MapVector_t * GetNodeInVector( unsigned node_num ); + vf_MapVector_t* GetNodeInVector(unsigned node_num) { + assert(node_num < m_nodenum); + return &(GetNode(node_num)->m_inMapVector); + } // GetNodeInVector /** - * Function receives OUT data flow vector of node. - * @param node_num - graph node number - * @return OUT data flow stack map vector of node. + * Gets OUT data flow vector for the node. + * @param node_num graph node number + * @return a reference to OUT data flow stack map vector * @note Assertion is raised if node_num is out of range. * @see vf_MapVector_t */ - vf_MapVector_t * GetNodeOutVector( unsigned node_num ); + vf_MapVector_t* GetNodeOutVector(unsigned node_num) { + assert(node_num < m_nodenum); + return &(GetNode(node_num)->m_outMapVector); + } // GetNodeOutVector /** * Function creates graph edges. @@ -1182,9 +1248,12 @@ vf_TypePool *m_type; ///< context type constraint collection char *m_error; ///< context error message method_handler m_method; ///< context method + bool m_is_constructor; ///< true if the + ///< method is a constructor vf_Graph_t *m_graph; ///< context control flow graph vf_VerifyPool_t *m_pool; ///< context memory pool vf_Code_t *m_code; ///< context code instruction of method + vf_BCode_t* m_bc; ///< bytecode to code mapping unsigned m_codeNum; ///< code instruction number unsigned m_nodeNum; ///< graph node number unsigned m_edgeNum; ///< graph edge number @@ -1217,6 +1286,7 @@ unsigned m_code_vector : 1; ///< print data flow node code instruction vectors unsigned m_merge_vector : 1; ///< print result of merge data flow vectors } m_dump; + }; // struct vf_Context /** @@ -1450,6 +1520,22 @@ vf_Context_t *context); /** + * Gets a class name from a constant pool. + * @param[in] klass a handle of the class + * @param[in] index the entry index + * @return a pointer to UTF8 constant pool entry + */ +static inline const char* +vf_get_cp_class_name( class_handler klass, + unsigned short index ) +{ + unsigned short class_name_index = + class_get_cp_class_name_index(klass, index); + const char* name = class_get_cp_utf8_bytes(klass, class_name_index); + return name; +} // vf_get_cp_class_name + +/** * Function creates valid type by given class name. * @param class_name - class name * @param context - verifier context @@ -1512,8 +1598,10 @@ vf_Context::ClearContext() { m_method = NULL; - m_graph = NULL; + m_is_constructor = false; + m_graph = NULL; m_code = NULL; + m_bc = NULL; m_codeNum = 0; m_nodeNum = 0; m_edgeNum = 0; @@ -1521,51 +1609,9 @@ } // vf_Context::vf_ClearContext /** - * Function checks basic block flag for given instruction. - * @param code - bytecode instruction - * @return If given instruction has basic block flag returns true, - * else returns false. - * @see vf_Code_t - */ -static inline bool -vf_is_begin_basic_block( vf_Code_t *code ) -{ - return (code->m_base & VF_FLAG_BEGIN_BASIC_BLOCK) != 0; -} // vf_is_begin_basic_block - -/** - * Function checks flags for given instruction. - * @param code - bytecode instruction - * @param flag - checked flags - * @return If given instruction has checked flag returns true, - * else returns false. - * @see vf_Code_t - */ -static inline bool -vf_is_instruction_has_flags( vf_Code_t *code, - unsigned flag) -{ - return ((unsigned)code->m_base & flag) != 0; -} // vf_is_instruction_has_flags - -/** - * Function checks what given instruction has any flags. - * @param code - bytecode instruction - * @return If given instruction has any flags returns true, - * else returns false. - * @see vf_Code_t - */ -static inline bool -vf_is_instruction_has_any_flags( vf_Code_t *code ) -{ - return (code->m_base != 0); -} // vf_is_instruction_has_flags - - -/** * Function sets error message of verifier. - * @param stream - stringstream object with message - * @param ctex - verifier context + * @param stream stringstream object with a message + * @param ctex a verifier context * @see vf_Context_t */ static inline void @@ -1589,15 +1635,91 @@ } // vf_set_error_message /** - * Checks version of class file - * @param context - verifier context + * Checks a version of a class file. + * @param context a verifier context + * @return true if a class version is less than 1.4 */ static inline bool -vf_is_class_version_14( vf_Context_t *context ) -{ +vf_is_class_version_14( vf_Context_t *context ) { return (class_get_version(context->m_class) < 49) ? true : false; } // vf_is_class_version_14 +/** + * Function returns branch target for a given branch number. + * @param code a reference to instruction + * @param branch_num a branch number + * @return an absolute bytecode position to which the executuion + * branches + */ +static inline int +vf_get_code_branch(vf_Code_t* code, unsigned branch_num) +{ + assert(branch_num < code->m_offcount); + return code->m_off[branch_num]; +} // vf_get_instruction_branch + +/** + * Allocates memory for a new stack map vector. + * @param[out] vector a reference to vector + * @param[in] len vector length + * @param[in] pool memory pool + */ +static inline void +vf_new_vector(vf_MapEntry_t** vector, + unsigned len, + vf_VerifyPool_t *pool) +{ + // create new vector + (*vector) = (vf_MapEntry_t*) vf_alloc_pool_memory(pool, + len * sizeof(vf_MapEntry_t)); + return; +} // vf_new_vector + +/** + * Sets a reference data type for a given stack map vector entry. + * @param[in, out] vector a reference to a stack map + * @param[in] num stack map index + * @param[in] type reference type + */ +static inline void +vf_set_vector_stack_entry_ref(vf_MapEntry_t* vector, + unsigned num, + vf_ValidType_t* type) +{ + // set a stack map vector entry by ref + vector[num].m_type = SM_REF; + vector[num].m_vtype = type; +} // vf_set_vector_stack_entry_ref + +/** + * Checks if a code range node ends with a specific + * instruction type. + * @param[in] context a verifier context + * @param[in] node_index the node identifier + * @return true if the edge is a subroutine call + */ +static inline bool +is_node_last_instruction(vf_Context_t *context, + unsigned node_index, unsigned flag) { + NodeHandle node = context->m_graph->GetNode( node_index ); + assert(VF_TYPE_NODE_CODE_RANGE == node->m_type); + return (VF_TYPE_INSTR_SUBROUTINE == context->m_code[node->m_end].m_type); +} + + +/** + * Checks if a graph edge is produced from jsr or + * jsr_w branch. + * @param[in] context a verifier context + * @param[in] edge the edge + * @return true if the edge is a subroutine call + */ +static inline bool +vf_is_subroutine_call(vf_Context_t *context, vf_Edge_t* edge) { + return (edge->m_start + 1 != edge->m_end) + && is_node_last_instruction(context, edge->m_start, VF_TYPE_INSTR_SUBROUTINE); +} + } // namespace Verifier using namespace Verifier; Index: vm/vmcore/src/verifier/Verifier.cpp =================================================================== --- vm/vmcore/src/verifier/Verifier.cpp (revision 504232) +++ vm/vmcore/src/verifier/Verifier.cpp (working copy) @@ -21,8 +21,8 @@ #include #include "ver_real.h" +#include "ver_subroutine.h" - /** * Debug flag macros */ @@ -30,11 +30,9 @@ #define VERIFY_CLASS 0 // Macro sets verification only for defined method #define VERIFY_METHOD 0 -// Macro dumps type constraints for class -#define VERIFY_DUMP_CONSTRAINT 0 -// Macro prints code array in stream -#define PRINT_CODE_ARRAY 0 + + /** * Set namespace Verifier */ @@ -115,29 +113,31 @@ ctex->m_type->SetMethod( ctex->m_method ); /** - * Allocate memory for code array - * (+2) for start-entry and end-entry instruction + * Allocate memory for code and bytecode annotations. */ - ctex->m_code = (vf_Code_t*)vf_alloc_pool_memory( ctex->m_pool, (len + 2 - + method_get_exc_handler_number( ctex->m_method )) * sizeof(vf_Code_t) ); + ctex->m_code = (vf_Code_t*)vf_alloc_pool_memory( ctex->m_pool, + len * sizeof(vf_Code_t) ); + ctex->m_bc = (vf_BCode_t*)vf_alloc_pool_memory( ctex->m_pool, + len * sizeof(vf_BCode_t) ); /** - * Parse bytecode, fill instruction codeArray + * Parse bytecode, fill instruction code. */ result = vf_parse_bytecode( ctex ); if( result != VER_OK ) { goto labelEnd_verifyClassBytecode; - } else if( ctex->m_dump.m_with_subroutine ) { - result = VER_NoSupportJSR; - goto labelEnd_verifyClassBytecode; } - /** * Build bytecode graph */ result = vf_create_graph( ctex ); - if( result != VER_OK ) { + if(ctex->m_dump.m_with_subroutine) { + result = VER_NoSupportJSR; goto labelEnd_verifyClassBytecode; + result = InlineSubroutines(ctex); + if (VER_OK != result) { + goto labelEnd_verifyClassBytecode; + } } /** @@ -167,39 +167,39 @@ * Function creates array of instruction branch offsets. */ static inline void -vf_create_instruction_offset( vf_Instr_t *instr, // given instruction - unsigned offcount, // number of offets - vf_VerifyPool_t *pool) // memory pool +vf_create_code_offset( vf_Code_t *code, // given instruction + unsigned offcount, // number of offets + vf_VerifyPool_t *pool) // memory pool { - assert( !instr->m_off ); - instr->m_off = (unsigned*)vf_alloc_pool_memory( pool, offcount * sizeof(unsigned) ); - instr->m_offcount = offcount; + assert( !code->m_off ); + code->m_off = (unsigned*)vf_alloc_pool_memory( pool, offcount * sizeof(unsigned) ); + code->m_offcount = offcount; return; } // vf_create_instruction_offset /** - * Function sets instruction branch offset. + * Function sets code branch offset. */ static inline void -vf_set_instruction_offset( vf_Instr_t *instr, // given instruction - unsigned offnum, // offset index in array - unsigned value) // offset value +vf_set_code_offset( vf_Code_t *code, // given instruction + unsigned offnum, // offset index in array + unsigned value) // offset value { - assert( instr->m_off && offnum < instr->m_offcount ); - instr->m_off[offnum] = value; + assert( code->m_off && offnum < code->m_offcount ); + code->m_off[offnum] = value; return; } // vf_set_instruction_offset /** - * Function creates branch offset array on 1 element and sets given value. + * Function creates a single branch. */ static inline void -vf_set_single_instruction_offset( vf_Instr_t *instr, // given instruction - unsigned value, // offset value - vf_VerifyPool_t *pool) // memory pool +vf_set_single_branch_offset( vf_Code_t *code, // given instruction + unsigned value, // offset value + vf_VerifyPool_t *pool) // memory pool { - vf_create_instruction_offset( instr, 1, pool ); - vf_set_instruction_offset( instr, 0, value ); + vf_create_code_offset( code, 1, pool ); + vf_set_code_offset( code, 0, value ); return; } // vf_set_single_instruction_offset @@ -235,7 +235,7 @@ * Function sets basic block attribute for instruction. */ static inline void -vf_set_basic_block_flag( vf_Instr_t *code ) // instruction +vf_set_basic_block_flag( vf_BCode_t *code ) // instruction { // set begin of basic block for instruction code->m_mark = 1; @@ -243,16 +243,16 @@ } // vf_set_basic_block_flag /** - * Function sets flags for code instruction. + * Sets flags for the instruction. */ static inline void -vf_set_instruction_flag( vf_Code_t *code, // code instruction - unsigned flag) // given flags +vf_set_code_type( vf_Code_t *code, // instruction + vf_CodeType_t type) // given flags { // set flag for instruction - code->m_base |= flag; + code->m_type = type; return; -} // vf_set_instruction_flag +} // vf_set_code_type /** * Function checks local number. @@ -264,10 +264,8 @@ { // check local variable number if( local >= maxlocal ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incorrect usage of local variable" ); + VERIFY_REPORT_METHOD( ctex, + "Incorrect usage of local variable" ); return VER_ErrorLocals; } return VER_OK; @@ -283,10 +281,8 @@ { if( offset < 0 || (unsigned)offset >= maxlen ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Instruction branch offset is out of range" ); + VERIFY_REPORT( ctex, + "Instruction branch offset is out of range" ); return VER_ErrorBranch; } return VER_OK; @@ -298,11 +294,12 @@ static inline unsigned vf_get_local_var_number( vf_Code_t *code, // code instruction unsigned char *bytecode, // method bytecode - unsigned *index_p) // index in bytecode array + unsigned *index_p, // index in bytecode array + bool wide_flag) // if this is a wide instruction { unsigned local; - if( (*index_p) != 1 && *((code - 1)->m_addr) == OPCODE_WIDE ) { + if(wide_flag) { // get number of local variable local = (unsigned)( (bytecode[(*index_p)] << 8)|(bytecode[(*index_p)+ 1]) ); // skip parameter (u2) @@ -315,18 +312,32 @@ } return local; } // vf_get_local_var_number - /** - * Function returns instruction branch offset for given branch number. + * Function parses local variable number from instruction bytecode. */ -static inline int -vf_get_instruction_branch( vf_Instr_t *code, // instruction - unsigned branch_num) // branch number +static inline unsigned +vf_get_local_var_number( vf_Code_t *code, // code instruction + unsigned char *bytecode, // method bytecode + unsigned *index_p, // index in bytecode array + bool *wide_flag) // if this is a wide instruction { - assert( branch_num < code->m_offcount ); - return code->m_off[branch_num]; -} // vf_get_instruction_branch + unsigned local; + if( (*wide_flag) ) { + // get number of local variable + local = (unsigned)( (bytecode[(*index_p)] << 8)|(bytecode[(*index_p)+ 1]) ); + // skip parameter (u2) + (*index_p) += 2; + *wide_flag = false; + } else { + // get number of local variable + local = (unsigned)bytecode[(*index_p)]; + // skip parameter (u1) + (*index_p)++; + } + return local; +} // vf_get_local_var_number + /** * Function receives half word (2 bytes) instruction branch offset * value from bytecode array. @@ -366,7 +377,7 @@ * sets into instruction and returns it. */ static inline int -vf_get_single_hword_branch_offset( vf_Instr_t *code, // instruction +vf_get_single_hword_branch_offset( vf_Code_t *code, // instruction unsigned code_pc, // offset in bytecode array unsigned char *bytecode, // bytecode array unsigned *index_p, // offset index in bytecode array @@ -375,7 +386,7 @@ // get first branch offset int offset = vf_get_hword_offset( code_pc, bytecode, index_p ); // create and set edge branch for instruction - vf_set_single_instruction_offset( code, offset, pool ); + vf_set_single_branch_offset( code, offset, pool ); return offset; } // vf_get_single_hword_branch_offset @@ -384,7 +395,7 @@ * sets into instruction and returns it. */ static inline int -vf_get_single_word_branch_offset( vf_Instr_t *code, // instruction +vf_get_single_word_branch_offset( vf_Code_t *code, // instruction unsigned code_pc, // offset in bytecode array unsigned char *bytecode, // bytecode array unsigned *index_p, // offset index in bytecode array @@ -393,7 +404,7 @@ // get first branch offset int offset = vf_get_word_offset( code_pc, bytecode, index_p ); // create and set edge branch for instruction - vf_set_single_instruction_offset( code, offset, pool ); + vf_set_single_branch_offset( code, offset, pool ); return offset; } // vf_get_single_word_branch_offset @@ -403,20 +414,20 @@ * Function returns received offset. */ static inline int -vf_get_double_hword_branch_offset( vf_Instr_t *code, // instruction - unsigned code_pc, // instruction offset in bytcode array - unsigned char *bytecode, // bytecode array - unsigned *index_p, // offset index in bytecode array - vf_VerifyPool_t *pool) // memory pool +vf_get_double_hword_branch_offset( vf_Code_t *code, // instruction + unsigned code_pc, // instruction offset in bytcode array + unsigned char *bytecode, // bytecode array + unsigned *index_p, // offset index in bytecode array + vf_VerifyPool_t *pool) // memory pool { // get first branch offset int offset = vf_get_hword_offset( code_pc, bytecode, index_p ); // create and set edge branches for instruction - vf_create_instruction_offset( code, 2, pool ); + vf_create_code_offset( code, 2, pool ); // set first edge branch for instruction - vf_set_instruction_offset( code, 0, offset ); + vf_set_code_offset( code, 0, offset ); // set second edge branch for instruction - vf_set_instruction_offset( code, 1, (*index_p) ); + vf_set_code_offset( code, 1, (*index_p) ); return offset; } // vf_get_double_hword_branch_offset @@ -426,20 +437,20 @@ * Function returns received offset. */ static inline int -vf_get_double_word_branch_offset( vf_Instr_t *code, // instruction - unsigned code_pc, // instruction offset in bytcode array - unsigned char *bytecode, // bytecode array - unsigned *index_p, // offset index in bytecode array - vf_VerifyPool_t *pool) // memory pool +vf_get_double_word_branch_offset( vf_Code_t *code, // instruction + unsigned code_pc, // instruction offset in bytcode array + unsigned char *bytecode, // bytecode array + unsigned *index_p, // offset index in bytecode array + vf_VerifyPool_t *pool) // memory pool { // get first branch offset int offset = vf_get_word_offset( code_pc, bytecode, index_p ); // create and set edge branches for instruction - vf_create_instruction_offset( code, 2, pool ); + vf_create_code_offset( code, 2, pool ); // set first edge branch for instruction - vf_set_instruction_offset( code, 0, offset ); + vf_set_code_offset( code, 0, offset ); // set second edge branch for instruction - vf_set_instruction_offset( code, 1, (*index_p) ); + vf_set_code_offset( code, 1, (*index_p) ); return offset; } // vf_get_double_word_branch_offset @@ -449,16 +460,16 @@ * Function returns received branch. */ static inline int -vf_get_tableswitch_alternative( vf_Instr_t *code, // instruction - unsigned code_pc, // offset in bytcode array - unsigned alternative, // number of tableswitch branch - unsigned char *bytecode, // bytecode array - unsigned *index_p) // offset index in bytecode array +vf_get_tableswitch_alternative( vf_Code_t *code, // instruction + unsigned code_pc, // offset in bytcode array + unsigned alternative, // number of tableswitch branch + unsigned char *bytecode, // bytecode array + unsigned *index_p) // offset index in bytecode array { // get first branch offset int offset = vf_get_word_offset( code_pc, bytecode, index_p ); // set first edge branch for instruction - vf_set_instruction_offset( code, alternative, offset ); + vf_set_code_offset( code, alternative, offset ); return offset; } // vf_get_tableswitch_alternative @@ -468,7 +479,7 @@ * Function returns number of alternatives. */ static inline int -vf_set_tableswitch_offsets( vf_Instr_t *code, // instruction +vf_set_tableswitch_offsets( vf_Code_t *code, // instruction unsigned code_pc, // instruction offset in bytecode array unsigned *index_p, // offset index in bytecode array unsigned char *bytecode, // bytecode array @@ -484,7 +495,7 @@ int high = vf_get_word_offset( code_pc, bytecode, &index ); int number = high - low + 2; // create tableswitch branches - vf_create_instruction_offset( code, number, pool ); + vf_create_code_offset( code, number, pool ); // set default offset vf_get_tableswitch_alternative( code, code_pc, 0, bytecode, &default_off ); // set another instruction offsets @@ -503,7 +514,7 @@ * Function returns number of alternatives. */ static inline Verifier_Result -vf_set_lookupswitch_offsets( vf_Instr_t *code, // instruction +vf_set_lookupswitch_offsets( vf_Code_t *code, // instruction unsigned code_pc, // instruction offset in bytecode unsigned *index_p, // offset index in bytecode array unsigned char *bytecode, // array of bytecode @@ -519,7 +530,7 @@ int number = vf_get_word_offset( 0, bytecode, &index ) + 1; *branch_p = number; // create and tableswitch branches - vf_create_instruction_offset( code, number, ctex->m_pool ); + vf_create_code_offset( code, number, ctex->m_pool ); // set default offset vf_get_tableswitch_alternative( code, code_pc, 0, bytecode, &default_off ); // set another instruction offsets @@ -530,10 +541,8 @@ if( old_key < key ) { old_key = key; } else if( key != INT_MIN ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Instruction lookupswitch has unsorted key values" ); + VERIFY_REPORT_METHOD( ctex, + "Instruction lookupswitch has unsorted key values" ); return VER_ErrorInstruction; } // get lookupswitch alternative and set offset to instruction @@ -550,20 +559,6 @@ ************************************************************/ /** - * Function allocates memory for new stack map vector. - */ -static inline void -vf_new_vector( vf_MapEntry_t **vector, // pointer to vector - unsigned len, // vector length - vf_VerifyPool_t *pool) // memory pool -{ - // create new vector - (*vector) = (vf_MapEntry_t*)vf_alloc_pool_memory( pool, - len * sizeof(vf_MapEntry_t) ); - return; -} // vf_new_vector - -/** * Function sets check type for a given stack map vector entry. */ static inline void @@ -665,19 +660,6 @@ } // vf_set_vector_stack_entry_double /** - * Function sets reference data type for given stack map vector entry. - */ -static inline void -vf_set_vector_stack_entry_ref( vf_MapEntry_t *vector, // stack map vector - unsigned num, // vector entry number - vf_ValidType_t *type) // reference type -{ - // set stack map vector entry by ref - vector[num].m_type = SM_REF; - vector[num].m_vtype = type; -} // vf_set_vector_stack_entry_ref - -/** * Function sets return address data type for given stack map vector entry. */ static inline void @@ -835,7 +817,7 @@ ************************************************************/ /** - * Function allocates memory for new code instruction IN stack map vector. + * Allocates memory for new code instruction in the IN stack map vector. */ static inline void vf_new_in_vector( vf_Code_t *code, // code instruction @@ -851,7 +833,7 @@ } // vf_new_in_vector /** - * Function sets check attribute for a code instruction IN stack map vector entry. + * Sets check attribute for a code instruction in the IN stack map vector entry. */ static inline void vf_set_in_vector_check( vf_Code_t *code, // code instruction @@ -1590,20 +1572,6 @@ } // vf_get_cp_nameandtype /** - * Function receives class name string. - * Function returns result of constant pool UTF8 entry check and class name string. - */ -static inline const char * -vf_get_cp_class_name( unsigned short index, // constant pool entry index - vf_Context_t *ctex) // verifier context -{ - unsigned short class_name_index = - class_get_cp_class_name_index( ctex->m_class, index ); - const char* name = class_get_cp_utf8_bytes( ctex->m_class, class_name_index ); - return name; -} // vf_get_cp_class_name - -/** * Function returns valid type string by given class name. */ static inline const char * @@ -1684,10 +1652,10 @@ assert(descr); // get class name if it's needed - if( class_name ) { + if (class_name) { unsigned short class_cp_index = - class_get_cp_ref_class_index( ctex->m_class, index ); - *class_name = vf_get_cp_class_name( class_cp_index, ctex ); + class_get_cp_ref_class_index(ctex->m_class, index); + *class_name = vf_get_cp_class_name(ctex->m_class, class_cp_index); } // get name and descriptor from NameAndType constant pool entry @@ -1836,10 +1804,8 @@ } // if class version is 1.4 verifier fails in default default: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Illegal type for constant pool entry #" + VERIFY_REPORT_METHOD( ctex, + "Illegal type for constant pool entry #" << index << (vf_is_class_version_14(ctex) ? ": CONSTANT_Integer, CONSTANT_Float or CONSTANT_String" @@ -1878,10 +1844,8 @@ vf_set_vector_stack_entry_long( cp_parse->field.f_vector, 0 ); break; default: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Illegal type in constant pool," + VERIFY_REPORT_METHOD( ctex, + "Illegal type in constant pool, " << index << ": CONSTANT_Double or CONSTANT_Long are expected" ); return VER_ErrorConstantPool; } @@ -1899,12 +1863,12 @@ vf_Context_t *ctex) // verifier context { // check constant pool index and type - unsigned short len = class_get_cp_size( ctex->m_class ); + unsigned short len = class_get_cp_size(ctex->m_class); CHECK_CONST_POOL_ID( index, len, ctex ); CHECK_CONST_POOL_CLASS( ctex, index ); if( cp_parse ) { // create valid type - const char *name = vf_get_cp_class_name( index, ctex ); + const char* name = vf_get_cp_class_name(ctex->m_class, index); // check result assert( name ); @@ -3401,8 +3365,8 @@ */ static inline void vf_opcode_ifeq( vf_Code_t *code, // code instruction - vf_Instr_t *icode1, // first branch instruction - vf_Instr_t *icode2, // second branch instruction + vf_BCode_t *icode1, // first branch instruction + vf_BCode_t *icode2, // second branch instruction vf_VerifyPool_t * pool) // memory pool { // set stack modifier for instruction @@ -3424,8 +3388,8 @@ */ static inline void vf_opcode_if_icmpeq( vf_Code_t *code, // code instruction - vf_Instr_t *icode1, // first branch instruction - vf_Instr_t *icode2, // second branch instruction + vf_BCode_t *icode1, // first branch instruction + vf_BCode_t *icode2, // second branch instruction vf_VerifyPool_t * pool) // memory pool { // set stack modifier for instruction @@ -3448,8 +3412,8 @@ */ static inline void vf_opcode_if_acmpeq( vf_Code_t *code, // code instruction - vf_Instr_t *icode1, // first branch instruction - vf_Instr_t *icode2, // second branch instruction + vf_BCode_t *icode1, // first branch instruction + vf_BCode_t *icode2, // second branch instruction vf_VerifyPool_t * pool) // memory pool { // set stack modifier for instruction @@ -3492,7 +3456,7 @@ vf_VerifyPool_t * pool) // memory pool { // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_RETURN ); + vf_set_code_type( code, VF_TYPE_INSTR_RETURN ); // set minimal stack for instruction vf_set_min_stack( code, 1 ); // create in vector @@ -3509,7 +3473,7 @@ vf_VerifyPool_t * pool) // memory pool { // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_RETURN ); + vf_set_code_type( code, VF_TYPE_INSTR_RETURN ); // set minimal stack for instruction vf_set_min_stack( code, 2 ); // create in vector @@ -3526,7 +3490,7 @@ vf_VerifyPool_t * pool) // memory pool { // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_RETURN ); + vf_set_code_type( code, VF_TYPE_INSTR_RETURN ); // set minimal stack for instruction vf_set_min_stack( code, 1 ); // create in vector @@ -3543,7 +3507,7 @@ vf_VerifyPool_t * pool) // memory pool { // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_RETURN ); + vf_set_code_type( code, VF_TYPE_INSTR_RETURN ); // set minimal stack for instruction vf_set_min_stack( code, 2 ); // create in vector @@ -3560,7 +3524,7 @@ vf_VerifyPool_t * pool) // memory pool { // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_RETURN ); + vf_set_code_type( code, VF_TYPE_INSTR_RETURN ); // set minimal stack for instruction vf_set_min_stack( code, 1 ); // create in vector @@ -3703,18 +3667,14 @@ } // check method name if( cp_parse.method.m_name[0] == '<' ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Must call initializers using invokespecial" ); + VERIFY_REPORT_METHOD( ctex, + "Must call initializers using invokespecial" ); return VER_ErrorConstantPool; } // check number of arguments if( cp_parse.method.m_inlen > 255 ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") The number of method parameters is limited to 255" ); + VERIFY_REPORT_METHOD( ctex, + "The number of method parameters is limited to 255" ); return VER_ErrorInstruction; } // set stack modifier for instruction @@ -3754,10 +3714,8 @@ } // check number of arguments if( cp_parse.method.m_inlen > 255 ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") The number of method parameters is limited to 255" ); + VERIFY_REPORT_METHOD( ctex, + "The number of method parameters is limited to 255" ); return VER_ErrorInstruction; } // set stack modifier for instruction @@ -3805,10 +3763,8 @@ // check created reference assert( cp_parse.field.f_vector->m_vtype->number == 1 ); if( cp_parse.field.f_vector->m_vtype->string[0][0] != 'L' ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Illegal creation of array" ); + VERIFY_REPORT_METHOD( ctex, + "Illegal creation of array" ); return VER_ErrorInstruction; } // set stack out vector @@ -3856,10 +3812,8 @@ vtype = ctex->m_type->NewType( "[J", 2 ); break; default: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incorrect type in instruction newarray" ); + VERIFY_REPORT_METHOD( ctex, + "Incorrect type in instruction newarray" ); return VER_ErrorInstruction; } // set minimal stack for instruction @@ -3949,7 +3903,7 @@ } // get array element type name - const char *name = vf_get_cp_class_name( cp_index, ctex ); + const char* name = vf_get_cp_class_name(ctex->m_class, cp_index); assert( name ); // create valid type string @@ -3964,10 +3918,8 @@ continue; } if( index > 255 ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Array with too many dimensions" ); + VERIFY_REPORT_METHOD( ctex, + "Array with too many dimensions" ); return VER_ErrorInstruction; } @@ -4014,7 +3966,7 @@ vf_Context_t *ctex) // verifier context { // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_THROW ); + vf_set_code_type( code, VF_TYPE_INSTR_THROW ); // set minimal stack for instruction vf_set_min_stack( code, 1 ); // create in vector @@ -4099,7 +4051,7 @@ static inline Verifier_Result vf_opcode_multianewarray( vf_Code_t *code, // code instruction unsigned short cp_index, // constant pool entry index - unsigned short dimension, // dimension of array + unsigned char dimensions, // dimension of array vf_Context_t *ctex) // verifier context { // check constant pool for instruction @@ -4109,7 +4061,7 @@ } // get array element type name - const char *name = vf_get_cp_class_name( cp_index, ctex ); + const char *name = vf_get_cp_class_name(ctex->m_class, cp_index); assert( name ); // get valid type string @@ -4123,17 +4075,13 @@ continue; } if( index > 255 ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Array with too many dimensions" ); + VERIFY_REPORT_METHOD( ctex, + "Array with too many dimensions" ); return VER_ErrorInstruction; } - if( dimension == 0 || index < dimension ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Illegal dimension argument" ); + if( dimensions == 0 || index < dimensions ) { + VERIFY_REPORT_METHOD( ctex, + "Illegal dimension argument" ); return VER_ErrorInstruction; } @@ -4141,12 +4089,12 @@ vf_ValidType_t *type = ctex->m_type->NewType( array, len ); // set stack modifier for instruction - vf_set_stack_modifier( code, 1 - dimension ); + vf_set_stack_modifier( code, 1 - dimensions ); // set minimal stack for instruction - vf_set_min_stack( code, dimension ); + vf_set_min_stack( code, dimensions ); // create in vector - vf_new_in_vector( code, dimension, ctex->m_pool ); - for( index = 0; index < dimension; index++ ) { + vf_new_in_vector( code, dimensions, ctex->m_pool ); + for( index = 0; index < dimensions; index++ ) { vf_set_in_vector_stack_entry_int( code, index ); } // create out vector @@ -4160,8 +4108,8 @@ */ static inline void vf_opcode_ifxnull( vf_Code_t *code, // code instruction - vf_Instr_t *icode1, // first branch instruction - vf_Instr_t *icode2, // second branch instruction + vf_BCode_t *icode1, // first branch instruction + vf_BCode_t *icode2, // second branch instruction vf_VerifyPool_t * pool) // memory pool { // set stack modifier for instruction @@ -4187,7 +4135,7 @@ vf_VerifyPool_t *pool) // memory pool { // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_SUBROUTINE ); + vf_set_code_type( code, VF_TYPE_INSTR_SUBROUTINE ); // set stack modifier for instruction vf_set_stack_modifier( code, 1 ); // create out vector @@ -4211,48 +4159,17 @@ } // vf_opcode_ret /** - * Function sets code instruction structure for end-entry. + * Parses bytecode, determines code instructions, fills code array and + * provides simple verifications. */ -static inline void -vf_create_end_entry( vf_Code_t *code, // code instruction - vf_Context_t *ctex) // verifier context -{ - int inlen, - outlen; - vf_MapEntry_t *invector, - *outvector; - - // set end-entry flag - vf_set_instruction_flag( code, VF_FLAG_BEGIN_BASIC_BLOCK | VF_FLAG_END_ENTRY); - // get method description - char *descr = (char*)method_get_descriptor( ctex->m_method ); - // parse description - vf_parse_description( descr, &inlen, &outlen ); - // set minimal stack for instruction - vf_set_min_stack( code, outlen ); - // create method vectors - vf_set_description_vector( descr, inlen, 0, outlen, &invector, &outvector, ctex ); - // set stack in vector - code->m_invector = outvector; - code->m_inlen = (unsigned short)outlen; - return; -} // vf_create_end_entry - -/** - * Function parse bytecode, determines code instructions, fills code array and - * provides checks of simple verifications. - */ static Verifier_Result -vf_parse_bytecode( vf_Context_t *ctex ) // verifier context +vf_parse_bytecode( vf_Context_t *ctex ) { - int offset, - number; - unsigned edges = 0, - index, - count, - bbCount = 0; - unsigned short local, - constIndex; + int offset; + unsigned index, count; + unsigned short local, const_index; + unsigned char u1; + Verifier_Result result = VER_OK; /** @@ -4261,52 +4178,61 @@ unsigned len = method_get_code_length( ctex->m_method ); unsigned char *bytecode = method_get_bytecode( ctex->m_method ); unsigned short locals = method_get_max_local( ctex->m_method ); - unsigned short handlcount = method_get_exc_handler_number( ctex->m_method ); - unsigned short constlen = class_get_cp_size( ctex->m_class ); - - /** - * Allocate memory for codeInstr - * +1 more instruction is the end of exception handler - */ - vf_Instr_t *codeInstr = (vf_Instr_t*)vf_alloc_pool_memory( ctex->m_pool, - (len + 1) * sizeof(vf_Instr_t) ); - /** - * Create start-entry instruction - */ - unsigned codeNum = 0; - vf_set_instruction_flag( &ctex->m_code[codeNum], - VF_FLAG_BEGIN_BASIC_BLOCK | VF_FLAG_START_ENTRY); - codeNum++; - /** - * Create handler instructions - */ - vf_Code_t *code; - for( index = 0, code = &ctex->m_code[codeNum]; - index < handlcount; - index++, codeNum++, code = &ctex->m_code[codeNum] ) - { - vf_set_instruction_flag( code, VF_FLAG_BEGIN_BASIC_BLOCK | VF_FLAG_HANDLER ); - } + // first instruction is always begin of basic block + vf_BCode_t* bc = ctex->m_bc; + bc[0].m_mark = 1; /** - * Define bytecode instructions and fill code array + * Parse bytecode instructions and fill a code array */ unsigned instr; unsigned branches; + unsigned codeNum = 0; + + vf_Code_t *code; vf_VerifyPool_t *pool = ctex->m_pool; - for( index = 0, code = &ctex->m_code[codeNum]; - index < len; - codeNum++, code = &ctex->m_code[codeNum] ) + for( index = 0; index < len; codeNum++) { + code = &ctex->m_code[codeNum]; code->m_addr = &bytecode[index]; - codeInstr[index].m_instr = codeNum; + // Note: + // bc[ index ].m_instr is assigned to a positive + // value to differentiate with non-assignd values: + // the correspondent index in vf_Context.m_code array + // is increased by one. + bc[ index ].m_instr = codeNum + 1; + + bool wide = (OPCODE_WIDE == bytecode[index]); /* 0xc4 */ + if (wide) { + switch (bytecode[++index]) // check the next instruction + { + case OPCODE_ILOAD: + case OPCODE_FLOAD: + case OPCODE_ALOAD: + case OPCODE_LLOAD: + case OPCODE_DLOAD: + case OPCODE_ISTORE: + case OPCODE_FSTORE: + case OPCODE_ASTORE: + case OPCODE_LSTORE: + case OPCODE_DSTORE: + case OPCODE_RET: + case OPCODE_IINC: + break; + default: + VERIFY_REPORT_METHOD( ctex, + "wide should be followed by iload, fload, aload, lload, dload, istore, fstore, astore, lstore, dstore, ret or iinc" ); + result = VER_ErrorInstruction; + goto labelEnd_vf_parse_bytecode; + } + } instr = index; // remember offset of instruction - index++; // skip bytecode + index++; // skip bytecode + switch( bytecode[instr] ) { case OPCODE_NOP: /* 0x00 */ - case OPCODE_WIDE: /* 0xc4 */ break; case OPCODE_ACONST_NULL: /* 0x01 */ vf_opcode_aconst_null( code, pool ); @@ -4339,10 +4265,10 @@ break; case OPCODE_LDC: /* 0x12 + u1 */ // get constant pool index - constIndex = (unsigned short)bytecode[index]; + const_index = (unsigned short)bytecode[index]; // skip constant pool index (u1) index++; - result = vf_opcode_ldcx( code, 1, constIndex, ctex ); + result = vf_opcode_ldcx( code, 1, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } @@ -4350,16 +4276,16 @@ case OPCODE_LDC_W: /* 0x13 + u2 */ case OPCODE_LDC2_W: /* 0x14 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_ldcx( code, bytecode[instr] - OPCODE_LDC, constIndex, ctex ); + result = vf_opcode_ldcx( code, bytecode[instr] - OPCODE_LDC, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_ILOAD: /* 0x15 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4367,7 +4293,7 @@ vf_opcode_iloadx( code, local, pool ); break; case OPCODE_LLOAD: /* 0x16 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local + 1, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4375,7 +4301,7 @@ vf_opcode_lloadx( code, local, pool ); break; case OPCODE_FLOAD: /* 0x17 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4383,7 +4309,7 @@ vf_opcode_floadx( code, local, pool ); break; case OPCODE_DLOAD: /* 0x18 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local + 1, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4391,7 +4317,7 @@ vf_opcode_dloadx( code, local, pool ); break; case OPCODE_ALOAD: /* 0x19 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4483,7 +4409,7 @@ vf_opcode_aaload( code, ctex ); break; case OPCODE_ISTORE: /* 0x36 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4491,7 +4417,7 @@ vf_opcode_istorex( code, local, pool ); break; case OPCODE_LSTORE: /* 0x37 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local + 1, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4499,7 +4425,7 @@ vf_opcode_lstorex( code, local, pool ); break; case OPCODE_FSTORE: /* 0x38 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4507,7 +4433,7 @@ vf_opcode_fstorex( code, local, pool ); break; case OPCODE_DSTORE: /* 0x39 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local + 1, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4515,7 +4441,7 @@ vf_opcode_dstorex( code, local, pool ); break; case OPCODE_ASTORE: /* 0x3a + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4693,7 +4619,7 @@ break; case OPCODE_IINC: /* 0x84 + u1|u2 + s1|s2 */ count = index; - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); count = index - count; result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { @@ -4761,7 +4687,7 @@ case OPCODE_IFGE: /* 0x9c + s2 */ case OPCODE_IFGT: /* 0x9d + s2 */ case OPCODE_IFLE: /* 0x9e + s2 */ - offset = vf_get_double_hword_branch_offset( &codeInstr[instr], + offset = vf_get_double_hword_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -4771,8 +4697,8 @@ if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_opcode_ifeq( code, &codeInstr[offset], - &codeInstr[index], pool ); + vf_opcode_ifeq( code, &bc[offset], + &bc[index], pool ); break; case OPCODE_IF_ICMPEQ: /* 0x9f + s2 */ case OPCODE_IF_ICMPNE: /* 0xa0 + s2 */ @@ -4780,7 +4706,7 @@ case OPCODE_IF_ICMPGE: /* 0xa2 + s2 */ case OPCODE_IF_ICMPGT: /* 0xa3 + s2 */ case OPCODE_IF_ICMPLE: /* 0xa4 + s2 */ - offset = vf_get_double_hword_branch_offset( &codeInstr[instr], + offset = vf_get_double_hword_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -4790,12 +4716,12 @@ if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_opcode_if_icmpeq( code, &codeInstr[offset], - &codeInstr[index], pool ); + vf_opcode_if_icmpeq( code, &bc[offset], + &bc[index], pool ); break; case OPCODE_IF_ACMPEQ: /* 0xa5 + s2 */ case OPCODE_IF_ACMPNE: /* 0xa6 + s2 */ - offset = vf_get_double_hword_branch_offset( &codeInstr[instr], + offset = vf_get_double_hword_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -4805,23 +4731,23 @@ if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_opcode_if_acmpeq( code, &codeInstr[offset], - &codeInstr[index], pool ); + vf_opcode_if_acmpeq( code, &bc[offset], + &bc[index], pool ); break; case OPCODE_GOTO: /* 0xa7 + s2 */ - offset = vf_get_single_hword_branch_offset( &codeInstr[instr], + offset = vf_get_single_hword_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_set_basic_block_flag( &codeInstr[offset] ); + vf_set_basic_block_flag( &bc[offset] ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_JSR: /* 0xa8 + s2 */ - offset = vf_get_double_hword_branch_offset( &codeInstr[instr], + offset = vf_get_double_hword_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -4833,43 +4759,42 @@ } vf_opcode_jsr( code, codeNum, pool ); ctex->m_dump.m_with_subroutine = 1; - vf_set_basic_block_flag( &codeInstr[offset] ); - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[offset] ); + vf_set_basic_block_flag( &bc[index] ); break; case OPCODE_RET: /* 0xa9 + u1|u2 */ - local = (unsigned short)vf_get_local_var_number( code, bytecode, &index ); + local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide ); result = vf_check_local_var_number( local, locals, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } vf_opcode_ret( code, local, pool ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_TABLESWITCH: /* 0xaa + pad + s4 * (3 + N) */ vf_opcode_switch( code, pool ); - branches = vf_set_tableswitch_offsets( &codeInstr[instr], + branches = vf_set_tableswitch_offsets( code, instr, &index, bytecode, pool); // check tableswitch branches and set begin of basic blocks for( count = 0; count < branches; count++ ) { - offset = vf_get_instruction_branch( &codeInstr[instr], count ); + offset = vf_get_code_branch( code, count ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_set_basic_block_flag( &codeInstr[offset] ); + vf_set_basic_block_flag( &bc[offset] ); } if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_LOOKUPSWITCH: /* 0xab + pad + s4 * 2 * (N + 1) */ vf_opcode_switch( code, pool ); - result = vf_set_lookupswitch_offsets( &codeInstr[instr], + result = vf_set_lookupswitch_offsets( code, instr, &index, bytecode, &branches, ctex); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; @@ -4877,142 +4802,136 @@ // check tableswitch branches and set begin of basic blocks for( count = 0; count < branches; count++ ) { - offset = vf_get_instruction_branch( &codeInstr[instr], count ); + offset = vf_get_code_branch( code, count ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_set_basic_block_flag( &codeInstr[offset] ); + vf_set_basic_block_flag( &bc[offset] ); } if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_IRETURN: /* 0xac */ vf_opcode_ireturn( code, pool ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_LRETURN: /* 0xad */ vf_opcode_lreturn( code, pool ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_FRETURN: /* 0xae */ vf_opcode_freturn( code, pool ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_DRETURN: /* 0xaf */ vf_opcode_dreturn( code, pool ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_ARETURN: /* 0xb0 */ vf_opcode_areturn( code, pool ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_RETURN: /* 0xb1 */ // set instruction flag - vf_set_instruction_flag( code, VF_FLAG_RETURN ); + vf_set_code_type( code, VF_TYPE_INSTR_RETURN ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_GETSTATIC: /* 0xb2 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_getstatic( code, constIndex, ctex ); + result = vf_opcode_getstatic( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_PUTSTATIC: /* 0xb3 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_putstatic( code, constIndex, ctex ); + result = vf_opcode_putstatic( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_GETFIELD: /* 0xb4 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_getfield( code, constIndex, ctex ); + result = vf_opcode_getfield( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_PUTFIELD: /* 0xb5 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_putfield( code, constIndex, ctex ); + result = vf_opcode_putfield( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_INVOKEVIRTUAL: /* 0xb6 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_invoke( code, constIndex, ctex ); + result = vf_opcode_invoke( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_INVOKESPECIAL: /* 0xb7 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_invokespecial( code, constIndex, ctex ); + result = vf_opcode_invokespecial( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_INVOKESTATIC: /* 0xb8 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_invoke( code, constIndex, ctex ); + result = vf_opcode_invoke( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_INVOKEINTERFACE:/* 0xb9 + u2 + u1 + u1 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_invoke( code, constIndex, ctex ); + result = vf_opcode_invoke( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } @@ -5020,10 +4939,8 @@ if( ctex->m_code[codeNum].m_inlen != (unsigned short)bytecode[index] || bytecode[index + 1] != 0 ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incorrect operand byte of invokeinterface"); + VERIFY_REPORT_METHOD( ctex, + "Incorrect operand byte of invokeinterface"); result = VER_ErrorInstruction; goto labelEnd_vf_parse_bytecode; } @@ -5032,30 +4949,30 @@ break; case OPCODE_NEW: /* 0xbb + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_new( code, constIndex, codeNum, ctex ); + result = vf_opcode_new( code, const_index, codeNum, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_NEWARRAY: /* 0xbc + u1 */ // get array type - number = (int)bytecode[index]; + u1 = (unsigned char)bytecode[index]; // skip parameter (u1) index++; - result = vf_opcode_newarray( code, (unsigned char)number, ctex ); + result = vf_opcode_newarray( code, u1, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_ANEWARRAY: /* 0xbd + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_anewarray( code, constIndex, ctex ); + result = vf_opcode_anewarray( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } @@ -5066,27 +4983,26 @@ case OPCODE_ATHROW: /* 0xbf */ vf_opcode_athrow( code, ctex ); // create and set edge branch to exit - vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_CHECKCAST: /* 0xc0 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_checkcast( code, constIndex, ctex ); + result = vf_opcode_checkcast( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_INSTANCEOF: /* 0xc1 + u2 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; - result = vf_opcode_instanceof( code, constIndex, ctex ); + result = vf_opcode_instanceof( code, const_index, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } @@ -5097,21 +5013,21 @@ break; case OPCODE_MULTIANEWARRAY: /* 0xc5 + u2 + u1 */ // get constant pool index - constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); + const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) ); // skip constant pool index (u2) index += 2; // get dimensions of array - number = (int)bytecode[index]; + u1 = (int)bytecode[index]; // skip dimensions of array (u1) index++; - result = vf_opcode_multianewarray( code, constIndex, (unsigned short)number, ctex ); + result = vf_opcode_multianewarray( code, const_index, u1, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } break; case OPCODE_IFNULL: /* 0xc6 + s2 */ case OPCODE_IFNONNULL: /* 0xc7 + s2 */ - offset = vf_get_double_hword_branch_offset( &codeInstr[instr], + offset = vf_get_double_hword_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -5121,23 +5037,23 @@ if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_opcode_ifxnull( &ctex->m_code[codeNum], &codeInstr[offset], - &codeInstr[index], pool ); + vf_opcode_ifxnull( &ctex->m_code[codeNum], &bc[offset], + &bc[index], pool ); break; case OPCODE_GOTO_W: /* 0xc8 + s4 */ - offset = vf_get_single_word_branch_offset( &codeInstr[instr], + offset = vf_get_single_word_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { goto labelEnd_vf_parse_bytecode; } - vf_set_basic_block_flag( &codeInstr[offset] ); + vf_set_basic_block_flag( &bc[offset] ); if( index < len ) { - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[index] ); } break; case OPCODE_JSR_W: /* 0xc9 + s4 */ - offset = vf_get_double_word_branch_offset( &codeInstr[instr], + offset = vf_get_double_word_branch_offset( code, instr, bytecode, &index, pool ); result = vf_check_branch_offset( offset, len, ctex ); if( result != VER_OK ) { @@ -5149,174 +5065,138 @@ } vf_opcode_jsr( code, codeNum, pool ); ctex->m_dump.m_with_subroutine = 1; - vf_set_basic_block_flag( &codeInstr[offset] ); - vf_set_basic_block_flag( &codeInstr[index] ); + vf_set_basic_block_flag( &bc[offset] ); + vf_set_basic_block_flag( &bc[index] ); break; case _OPCODE_UNDEFINED: /* 0xba */ default: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Unknown instruction bytecode" ); + VERIFY_REPORT_METHOD( ctex, + "Unknown instruction bytecode" ); result = VER_ErrorInstruction; goto labelEnd_vf_parse_bytecode; } } - /** - * Create end-entry instruction - */ - code = ctex->m_code; - vf_create_end_entry( &code[codeNum], ctex ); - codeInstr[index].m_instr = codeNum; - codeNum++; + if (index > len) { + VERIFY_REPORT_METHOD( ctex, + "The last instruction doesn't fit bytecode array" ); + result = VER_ErrorCodeEnd; + goto labelEnd_vf_parse_bytecode; + } /** - * Set handler basic blocks + * Set handler basic blocks. */ - edges = 0; - for( index = 0; index < handlcount; index++ ) { - // check instruction range - unsigned short start_pc; - unsigned short end_pc; - unsigned short handler_pc; + unsigned short handler_count = method_get_exc_handler_number( ctex->m_method ); + unsigned short handler_index; + unsigned short constLen = class_get_cp_size( ctex->m_class ); + for( handler_index = 0; + handler_index < handler_count; handler_index++ ) { + unsigned short start_pc, end_pc, handler_pc; unsigned short handler_cp_index; - method_get_exc_handler_info( ctex->m_method, (unsigned short)index, &start_pc, &end_pc, - &handler_pc, &handler_cp_index ); - if( ( start_pc >= len ) || ( end_pc > len ) || ( handler_pc >= len ) ) - { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Handler pc is out of range" ); + method_get_exc_handler_info( ctex->m_method, + handler_index, &start_pc, &end_pc, &handler_pc, + &handler_cp_index ); + // check instruction range + if((start_pc >= len) || (end_pc > len) || (handler_pc >= len)) { + VERIFY_REPORT_METHOD( ctex, + "Exception handler pc is out of range" ); result = VER_ErrorHandler; goto labelEnd_vf_parse_bytecode; } - // check constant pool index - CHECK_HANDLER_CONST_POOL_ID( handler_cp_index, constlen, ctex ); - CHECK_HANDLER_CONST_POOL_CLASS( ctex, handler_cp_index ); - // check instruction relations - if( (codeInstr[ start_pc ].m_instr == 0) - || (codeInstr[ end_pc ].m_instr == 0) - || (codeInstr[ handler_pc ].m_instr == 0) ) + if(start_pc >= end_pc) { + VERIFY_REPORT_METHOD( ctex, + "Exception handler range starting point should be before ending point" ); + result = VER_ErrorHandler; + goto labelEnd_vf_parse_bytecode; + } + + // if end_pc == len, set it to 0 + end_pc %= len; + + // check that handlers point to instruction + // boundaries + if( (bc[ start_pc ].m_instr == 0) + || (bc[ end_pc ].m_instr == 0) + || (bc[ handler_pc ].m_instr == 0) ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Handler pc is out of instruction set" ); + VERIFY_REPORT_METHOD( ctex, + "Handler pc is out of instruction set" ); result = VER_ErrorHandler; goto labelEnd_vf_parse_bytecode; } + // set handler basic blocks - codeInstr[ start_pc ].m_mark = 1; - codeInstr[ end_pc ].m_mark = 1; - codeInstr[ handler_pc ].m_mark = 1; + bc[ start_pc ].m_mark = 1; + bc[ end_pc ].m_mark = 1; + bc[ handler_pc ].m_mark = 1; + } - /** - * Set handler branch offset - */ - edges++; - code[index + 1].m_offcount = 1; - code[index + 1].m_off = (unsigned*)vf_alloc_pool_memory( pool, - sizeof(unsigned) ); - // fill offset array for code instruction - code[index + 1].m_off[0] = codeInstr[ handler_pc ].m_instr; - // create handler valid type - vf_ValidType_t *type = NULL; - if( handler_cp_index ) { - const char* name = vf_get_cp_class_name( handler_cp_index, ctex ); - assert(name); + /** + * Count edges from basic blocks from exception range to the + * corresponding exception handlers. + */ + unsigned edges = 0; + for( handler_index = 0; + handler_index < handler_count; handler_index++ ) { + unsigned short start_pc, end_pc, handler_pc; + unsigned short handler_cp_index; + method_get_exc_handler_info( ctex->m_method, handler_index, + &start_pc, &end_pc, &handler_pc, &handler_cp_index ); - type = vf_create_class_valid_type( name, ctex ); - // set restriction for handler class - if( ctex->m_vtype.m_throwable->string[0] != type->string[0] ) { - ctex->m_type->SetRestriction( ctex->m_vtype.m_throwable->string[0], - type->string[0], 0, VF_CHECK_SUPER ); - } + // number of basic blocks in the exception range + unsigned handler_edges = 0; + for( count = start_pc; count < end_pc; count++ ) { + handler_edges += bc[ count ].m_mark; } - // create out vector for handler - vf_new_out_vector( &code[index + 1], 1, pool ); - vf_set_out_vector_stack_entry_ref( &code[index + 1], 0, type ); - /** - * Set handler branches - * Set handler branches to last instructions of basic blocks - */ - for( count = start_pc + 1; count <= end_pc; count++ ) { - if( count < len && codeInstr[count].m_mark ) { - // calculate code instruction number - instr = codeInstr[count].m_instr - 1; - // check existence of handler array - if( code[instr].m_handler == NULL ) { - // create handler array for code instruction - code[instr].m_handler = - (unsigned char*)vf_alloc_pool_memory( pool, - handlcount * sizeof(unsigned char) ); - } - // count handler edges - edges++; - // set handler branch - code[instr].m_handler[index] = 1; - } - } + edges += handler_edges; } /** - * Initialize basic block count - * Include start-entry basic block, handler basic blocks, - * end-entry basic block. + * Initialize a node counter with handler nodes and + * terminator nodes. */ - bbCount = 1 + handlcount + 1; + unsigned nodes = handler_count + 2; /** - * Set code offsets - * Check code instructions + * Check code offsets, count basic blocks and edges. */ for( index = 0; index < len; index++ ) { - if( !index || codeInstr[index].m_mark ) { - // first instruction is always begin of basic block - if( (count = codeInstr[index].m_instr) == 0 ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Illegal target of jump or branch" ); + instr = bc[ index ].m_instr; + if (instr == 0) { + if( bc[ index ].m_mark ) { + VERIFY_REPORT_METHOD( ctex, + "Illegal target of jump or branch" ); result = VER_ErrorBranch; goto labelEnd_vf_parse_bytecode; + } else { + continue; } - vf_set_instruction_flag( &code[count], VF_FLAG_BEGIN_BASIC_BLOCK ); - bbCount++; - if( !index || code[count - 1].m_offcount == 0 ) { - // considering first edge from start-entry to first instruction - // count only edges that catenate 2 nearby instructions - edges++; - } } - if( codeInstr[index].m_offcount ) { - // calculate code instruction number - instr = codeInstr[index].m_instr; - // create offset array for code instruction - edges += codeInstr[index].m_offcount; - code[instr].m_offcount = codeInstr[index].m_offcount; - code[instr].m_off = codeInstr[index].m_off; - // fill offset array for code instruction - for( count = 0; count < codeInstr[index].m_offcount; count++ ) { - offset = codeInstr[index].m_off[count]; - if( offset == -1 ) { - code[instr].m_off[count] = codeNum - 1; - } else { - code[instr].m_off[count] = codeInstr[offset].m_instr; - } - } + + code = &ctex->m_code[instr - 1]; + if( bc[ index ].m_mark ) { + code->m_basic_block_start = true; + nodes++; } + + if( code->m_offcount ) { + // basic block should start next, so we will + // count one branch anyway + edges += code->m_offcount - 1; + } } -labelEnd_vf_parse_bytecode: - /** - * Free allocated memory + * Each node except the ending node emits at least one branch. */ + edges += nodes - 1; + +labelEnd_vf_parse_bytecode: + ctex->m_codeNum = codeNum; - ctex->m_nodeNum = bbCount; + ctex->m_nodeNum = nodes; ctex->m_edgeNum = edges; #if _VERIFY_DEBUG @@ -5336,50 +5216,50 @@ void vf_dump_bytecode( vf_Context_t *ctex ) // verifier context { - unsigned char* bytecode; - unsigned index, - count, - handlcount; - vf_Code_t *code = ctex->m_code; - - bytecode = method_get_bytecode( ctex->m_method ); - handlcount = method_get_exc_handler_number( ctex->m_method ); VERIFY_DEBUG( "======================== VERIFIER METHOD DUMP ========================" ); VERIFY_DEBUG( "Method: " << class_get_name( ctex->m_class ) << "." << method_get_name( ctex->m_method ) << method_get_descriptor( ctex->m_method ) << endl ); VERIFY_DEBUG( "0 [-]: -> START-ENTRY" ); - for( index = 0; index < handlcount; index++ ) { - VERIFY_DEBUG( index + 1 << " [-]: -> HANDLER #" << index + 1 ); - if( code[index + 1].m_offcount ) { - for( count = 0; count < code[index + 1].m_offcount; count++ ) - if( code[index + 1].m_off[count] == ctex->m_codeNum - 1 ) { - VERIFY_DEBUG( " --> " << code[index + 1].m_off[count] << " [-]" ); - } else { - VERIFY_DEBUG( " --> " << code[index + 1].m_off[count] - << " [" - << code[ code[index + 1].m_off[count] ].m_addr - - bytecode << "]" ); - } - } + + unsigned short handler_count = + method_get_exc_handler_number( ctex->m_method ); + for( unsigned short handler_index = 0; + handler_index < handler_count; handler_index++ ) { + VERIFY_DEBUG( handler_index + 1 << " [-]: -> HANDLER #" << handler_index + 1 ); + unsigned short start_pc, end_pc, handler_pc; + unsigned short handler_cp_index; + method_get_exc_handler_info( ctex->m_method, + handler_index, &start_pc, &end_pc, + &handler_pc, &handler_cp_index ); + + VERIFY_DEBUG( + " from " << ctex->m_bc[start_pc].m_instr + handler_count + << " [" << start_pc << "]" + " to " << ctex->m_bc[end_pc].m_instr + handler_count + << " [" << end_pc << "]" + " --> " << ctex->m_bc[handler_pc].m_instr + handler_count + << " [" << handler_pc << "]" + ", CP type " << handler_cp_index ); } - for( index = handlcount + 1; index < ctex->m_codeNum - 1; index++ ) { - VERIFY_DEBUG( index << " [" << code[index].m_addr - bytecode << "]:" - << (vf_is_begin_basic_block( &code[index] ) ? " -> " : " ") - << ((code[index].m_stack < 0) ? "" : " " ) - << code[index].m_stack - << "|" << code[index].m_minstack << " " - << vf_opcode_names[*(code[index].m_addr)] ); - if( code[index].m_offcount ) { - for( count = 0; count < code[index].m_offcount; count++ ) - if( code[index].m_off[count] == ctex->m_codeNum - 1 ) { - VERIFY_DEBUG( " --> " << code[index].m_off[count] << " [-]" ); - } else { - VERIFY_DEBUG( " --> " << code[index].m_off[count] - << " [" - << code[ code[index].m_off[count] ].m_addr - - bytecode << "]" ); - } + + unsigned char* bytecode = + method_get_bytecode( ctex->m_method ); + unsigned index = handler_count + 1; + vf_Code_t* code = ctex->m_code; + for(; index < ctex->m_codeNum + handler_count + 1; index++, code++) { + VERIFY_DEBUG( index + << " [" << code->m_addr - bytecode << "]:" + << ((code->m_basic_block_start) ? " -> " : " ") + << ((code->m_stack < 0) ? "" : " " ) + << code->m_stack + << "|" << code->m_minstack << " " + << vf_opcode_names[*(code->m_addr)] ); + for( unsigned count = 0; count < code->m_offcount; count++ ) { + unsigned offset = code->m_off[count]; + VERIFY_DEBUG( " --> " + << ctex->m_bc[offset].m_instr + handler_count + << " [" << offset << "]" ); } } VERIFY_DEBUG( index << " [-]: -> END-ENTRY" << endl ); @@ -5438,7 +5318,7 @@ memcpy( &type_name[1], class_name, class_name_len ); type_name[0] = 'L'; type_name[class_name_len + 1] = '\0'; - context.m_vtype.m_class = context.m_type->NewType( type_name, class_name_len + 1 ); + context. m_vtype.m_class = context.m_type->NewType( type_name, class_name_len + 1 ); context.m_vtype.m_throwable = context.m_type->NewType( "Ljava/lang/Throwable", 20 ); context.m_vtype.m_object = context.m_type->NewType( "Ljava/lang/Object", 17 ); context.m_vtype.m_array = context.m_type->NewType( "[Ljava/lang/Object", 18 ); @@ -5467,6 +5347,9 @@ //context.m_dump.m_node_vector = 1; //context.m_dump.m_code_vector = 1; //context.m_dump.m_merge_vector = 1; + // context.m_dump.m_dot_graph = 1; + //context.m_dump.m_code = 1; + //context.m_dump.m_dot_mod_graph = 1; result = vf_verify_method_bytecode( &context ); context.ClearContext(); } @@ -5496,7 +5379,7 @@ *message = context.m_error; #if _VERIFY_DEBUG if( result != VER_OK ) { - TRACE2("verifier", "VerifyError: " << (context.m_error ? context.m_error : "NULL") ); + VERIFY_DEBUG( "VerifyError: " << (context.m_error ? context.m_error : "NULL") ); } #endif // _VERIFY_DEBUG Index: vm/vmcore/src/verifier/ver_utils.cpp =================================================================== --- vm/vmcore/src/verifier/ver_utils.cpp (revision 504232) +++ vm/vmcore/src/verifier/ver_utils.cpp (working copy) @@ -1031,52 +1031,36 @@ switch( check ) { case VF_CHECK_PARAM: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Incompatible argument for function" ); + VERIFY_REPORT_METHOD( ctex, + "Incompatible argument for function" ); break; case VF_CHECK_ASSIGN: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Incompatible types for field assignment" ); + VERIFY_REPORT( ctex, + "Incompatible types for field assignment" ); break; case VF_CHECK_ASSIGN_WEAK: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Incompatible types for array assignment" ); + VERIFY_REPORT_METHOD( ctex, + "Incompatible types for array assignment" ); break; case VF_CHECK_SUPER: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Exception class not a subclass of Throwable" ); + VERIFY_REPORT_METHOD( ctex, + "Exception class not a subclass of Throwable" ); break; case VF_CHECK_ACCESS_FIELD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Bad access to protected field" ); + VERIFY_REPORT_METHOD( ctex, + "Bad access to protected field" ); break; case VF_CHECK_ACCESS_METHOD: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Bad access to protected method" ); + VERIFY_REPORT_METHOD( ctex, + "Bad access to protected method" ); break; case VF_CHECK_DIRECT_SUPER: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Call to wrong initialization method" ); + VERIFY_REPORT_METHOD( ctex, + "Call to wrong initialization method" ); break; case VF_CHECK_INVOKESPECIAL: - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( method ) - << method_get_descriptor( method ) - << ") Incompatible object argument for invokespecial" ); + VERIFY_REPORT_METHOD( ctex, + "Incompatible object argument for invokespecial" ); break; default: DIE( "Verifier: vf_set_error: unknown check type" ); @@ -1292,7 +1276,7 @@ return VER_OK; } if( method_is_protected( method ) ) { - if( instance_name[0] == '[' && !memcmp( method_get_name( method ), "clone", 6 ) ) { + if( instance_name[0] == '[' && !memcmp( method_get_name( method ), "clone", 7 ) ) { // for arrays function clone is public } else { need_check = true; Index: vm/vmcore/src/verifier/ver_dataflow.cpp =================================================================== --- vm/vmcore/src/verifier/ver_dataflow.cpp (revision 504232) +++ vm/vmcore/src/verifier/ver_dataflow.cpp (working copy) @@ -152,7 +152,7 @@ } // dump stack vector *stream << "S:"; - for( index = 0; index < vector->m_deep; index++ ) { + for( index = 0; index < vector->m_depth; index++ ) { vf_dump_vector_entry( &vector->m_stack[index], stream ); if( vector->m_stack[index].m_is_local ) { *stream << "!"; @@ -162,7 +162,7 @@ } *stream << endl; // dump stack references - for( index = 0; index < vector->m_deep; index++ ) { + for( index = 0; index < vector->m_depth; index++ ) { if( vector->m_stack[index].m_type == SM_REF ) { *stream << " REF #" << index << ": "; } else if( vector->m_stack[index].m_type == SM_UNINITIALIZED ) { @@ -288,8 +288,8 @@ } // merge stack map vector - assert( first->m_deep == second->m_deep ); - for( index = 0; index < second->m_deep; index++ ) { + assert( first->m_depth == second->m_depth ); + for( index = 0; index < second->m_depth; index++ ) { // merge entries type if( first->m_stack[index].m_type == SM_TOP ) { // no need to merge @@ -344,8 +344,8 @@ data->m_local[index] = zero; } // copy stack - data->m_deep = source->m_deep; - for( index = 0; index < source->m_deep; index++ ) { + data->m_depth = source->m_depth; + for( index = 0; index < source->m_depth; index++ ) { data->m_stack[index] = source->m_stack[index]; } for( ; index < data->m_maxstack; index++ ) { @@ -365,7 +365,7 @@ if( first->m_maxlocal != second->m_maxlocal || first->m_maxstack != second->m_maxstack || first->m_number != second->m_number - || first->m_deep != second->m_deep ) + || first->m_depth != second->m_depth ) { return false; } @@ -383,7 +383,7 @@ } } // compare stack - for( index = 0; index < first->m_deep; index++ ) { + for( index = 0; index < first->m_depth; index++ ) { if( first->m_stack[index].m_type != second->m_stack[index].m_type || first->m_stack[index].m_vtype != second->m_stack[index].m_vtype ) { @@ -460,25 +460,17 @@ // check initialization if( source->m_type == SM_UNINITIALIZED && target->m_type != SM_UNINITIALIZED) { if( (source->m_new == 0 && target->m_ctype == VF_CHECK_ACCESS_FIELD) - || (local_init == false && target->m_ctype == VF_CHECK_UNINITIALIZED_THIS) - || (!ctex->m_dump.m_verify && source->m_new == 0 - && target->m_ctype == VF_CHECK_UNINITIALIZED_THIS) ) + || (local_init == false && target->m_ctype == VF_CHECK_UNINITIALIZED_THIS) ) { // 1. In initialization method instance fields of this // that are declared in the current class may be assigned - // before calling any instance initialization method. + // before calling any instance initialization method // 2. Uninitialized class instance can be stored in // a local variable if no backward branch is taken or // the code isn't protected by exception handler. - // 3. In default mode (without any verifier control options) - // uninitiliazed class reference in initialization method - // can be stored in a local variable if backward branch is - // taken or the code is protected by exception handler. } else { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Uninitialized reference usage" ); + VERIFY_REPORT_METHOD( ctex, + "Uninitialized reference usage" ); return VER_ErrorDataFlow; } } @@ -721,16 +713,16 @@ * Function clears stack map vector. */ static inline void -vf_clear_stack( vf_MapVector_t *vector ) // map vector +vf_clear_stack( vf_MapVector_t *vector ) // stack map vector { + unsigned short index; vf_MapEntry_t zero_entry = {0}; // zero stack vector - for( unsigned index = 0; index < vector->m_deep; index++ ) { + for( index = 0; index < vector->m_depth; index++ ) { vector->m_stack[index] = zero_entry; } - vector->m_deep = 0; - + vector->m_depth = 0; return; } // vf_clear_stack @@ -810,10 +802,8 @@ // check entry types result = vf_check_entry_refs( entry, newvector, local_init, ctex ); if( result != VER_OK ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Incompatible types for array assignment" ); + VERIFY_REPORT_METHOD( ctex, + "Incompatible types for array assignment" ); return result; } break; @@ -822,10 +812,8 @@ result = vf_check_entry_refs( entry, vector, local_init, ctex ); if( result != VER_OK ) { if( !ctex->m_error ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Data flow analysis error" ); + VERIFY_REPORT_METHOD( ctex, + "Data flow analysis error" ); } return result; } @@ -835,18 +823,14 @@ // check entry references if( entry->m_type == SM_REF ) { // double initialization - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Double initialization of object reference" ); + VERIFY_REPORT_METHOD( ctex, + "Double initialization of object reference" ); return VER_ErrorDataFlow; } result = vf_check_entry_refs( entry, vector, local_init, ctex ); if( result != VER_OK ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Data flow analysis error (uninitialized)" ); + VERIFY_REPORT( ctex, + "Data flow analysis error (uninitialized)" ); return result; } // check initialization class in constructor @@ -865,10 +849,8 @@ // check entry types result = vf_check_entry_types( entry, vector, local_init, ©, ctex ); if( result != VER_OK ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Data flow analysis error" ); + VERIFY_REPORT_METHOD( ctex, + "Data flow analysis error" ); return result; } } @@ -897,8 +879,8 @@ vf_MapEntry_t zero_entry = {0}; // set stack vector - assert( invector->m_deep - instr->m_minstack >= 0 ); - vf_MapEntry_t *stack = invector->m_stack + invector->m_deep - instr->m_minstack; + assert( invector->m_depth - instr->m_minstack >= 0 ); + vf_MapEntry_t *stack = invector->m_stack + invector->m_depth - instr->m_minstack; // set locals vector vf_MapEntry_t *locals = invector->m_local; // check instruction in vector @@ -910,18 +892,23 @@ } // create out vector for return instructions - if( vf_is_instruction_has_flags( instr, VF_FLAG_RETURN ) ) { + if( VF_TYPE_INSTR_RETURN == instr->m_type ) { // clear stack - unsigned deep = invector->m_deep; + unsigned deep = invector->m_depth; vf_clear_stack( invector ); // set result vector stack deep - invector->m_deep = (unsigned short)(deep + instr->m_stack); + invector->m_depth = (unsigned short)(deep + instr->m_stack); // set out vector vf_set_return_out_vector( invector->m_stack, buf, instr->m_invector, instr->m_inlen, ctex ); return VER_OK; - } else if( vf_is_instruction_has_flags( instr, VF_FLAG_THROW ) ) { + } else if( VF_TYPE_INSTR_THROW == instr->m_type ) { + // clear stack + unsigned deep = invector->m_depth; + vf_clear_stack( invector ); // set result vector stack deep + invector->m_depth = (unsigned short)(deep + instr->m_stack); + // set out vector invector->m_stack->m_type = SM_TERMINATE; return VER_OK; } @@ -944,7 +931,7 @@ } } // init stack reference - for( index = 0; index < (unsigned)invector->m_deep - instr->m_minstack; index++ ) { + for( index = 0; index < (unsigned)invector->m_depth - instr->m_minstack; index++ ) { if( invector->m_stack[index].m_type == SM_UNINITIALIZED && invector->m_stack[index].m_new == buf[0].m_new ) { @@ -955,8 +942,8 @@ } // set instruction OUT vector - invector->m_deep = (unsigned short )(invector->m_deep + instr->m_stack); - assert( invector->m_deep <= invector->m_maxstack ); + invector->m_depth = (unsigned short )(invector->m_depth + instr->m_stack); + assert( invector->m_depth <= invector->m_maxstack ); index = invector->m_number; vf_set_instruction_out_vector( instr, stack, locals, &invector->m_number, buf, ctex ); assert( invector->m_number <= invector->m_maxlocal ); @@ -972,19 +959,24 @@ } // vf_get_instruction_out_vector /** - * Function receives handler OUT data flow vector. + * Copies a stored handler vector to the out vector. + * @param[in, out] invector IN handler vector + * @param[in] handler_vector stored handler vector */ static inline Verifier_Result -vf_get_handler_out_vector( vf_Code_t *instr, // handler code instruction - vf_MapVector_t *invector) // incoming data flow vector +vf_get_handler_out_vector(vf_MapVector_t* invector, + vf_MapVector_t* handler_vector) { + assert(0 == invector->m_depth); + assert(1 == handler_vector->m_depth); + assert(SM_REF == handler_vector->m_stack->m_type); + // set handler out vector - assert( invector->m_deep == 0 ); - assert( instr->m_outlen == 1 ); - invector->m_stack->m_type = instr->m_outvector->m_type; - invector->m_stack->m_vtype = instr->m_outvector->m_vtype; + invector->m_stack->m_type = handler_vector->m_stack->m_type; + invector->m_stack->m_vtype = handler_vector->m_stack->m_vtype; + // set modify vector value - invector->m_deep++; + invector->m_depth = 1; return VER_OK; } // vf_get_handler_out_vector @@ -999,53 +991,50 @@ { unsigned index, instruction; - vf_Code_t *instr; Verifier_Result result; // get node instruction number vf_Graph_t *graph = ctex->m_graph; - instruction = graph->GetNodeLastInstr( node_num ) - - graph->GetNodeFirstInstr( node_num ) + 1; - // get first instruction - instr = &ctex->m_code[graph->GetNodeFirstInstr( node_num )]; + vf_Node_t* node = graph->GetNode( node_num ); /** * For start-entry node doesn't need to check data flow */ - if( vf_is_instruction_has_flags( instr, VF_FLAG_START_ENTRY ) ) { - assert( instruction == 1 ); + if (VF_TYPE_NODE_START_ENTRY == node->m_type) { return VER_OK; - } else if( vf_is_instruction_has_flags( instr, VF_FLAG_HANDLER ) ) { - assert( instruction == 1 ); - // set out vector for handler node - result = vf_get_handler_out_vector( instr, invector ); + } + + if (VF_TYPE_NODE_HANDLER == node->m_type) { + // set OUT vector for a handler node + return vf_get_handler_out_vector(invector, &node->m_outMapVector); + } + + // get first instruction + vf_Code_t* instr = &ctex->m_code[graph->GetNodeFirstInstr( node_num )]; + instruction = graph->GetNodeLastInstr( node_num ) + - graph->GetNodeFirstInstr( node_num ) + 1; + + // set out vector for each instruction + for( index = 0; index < instruction; index++ ) { + if( instr[index].m_inlen + instr[index].m_outlen == 0 + && ( VF_TYPE_INSTR_NONE == instr->m_type ) ) + { + continue; + } else { + result = vf_get_instruction_out_vector( node_num, &instr[index], invector, + buf, ctex ); + } if( result != VER_OK ) { return result; } - } else { - // set out vector for each instruction - for( index = 0; index < instruction; index++ ) { - if( instr[index].m_inlen + instr[index].m_outlen == 0 - && !vf_is_instruction_has_any_flags( instr ) ) - { - continue; - } else { - result = vf_get_instruction_out_vector( node_num, &instr[index], invector, - buf, ctex ); - } - if( result != VER_OK ) { - return result; - } #if _VERIFY_DEBUG - if( ctex->m_dump.m_code_vector ) { - // dump instruction OUT vector - cerr << "-------------- instruction #" << index << " out: " << endl; - vf_dump_vector( invector, &instr[index], &cerr ); - } -#endif // _VERIFY_DEBUG + if( ctex->m_dump.m_code_vector ) { + // dump instruction OUT vector + cerr << "-------------- instruction #" << index << " out: " << endl; + vf_dump_vector( invector, &instr[index], &cerr ); } +#endif // _VERIFY_DEBUG } - return VER_OK; } // vf_set_node_out_vector @@ -1104,19 +1093,18 @@ #endif // _VERIFY_DEBUG // check stack modifier - assert( (int)((graph->GetNodeOutVector( node_num )->m_deep - - graph->GetNodeInVector( node_num )->m_deep)) + assert( (int)((graph->GetNodeOutVector( node_num )->m_depth + - graph->GetNodeInVector( node_num )->m_depth)) == graph->GetNodeStackModifier( node_num ) ); return VER_OK; } // vf_create_node_vectors /** - * Function checks data flow for end graph node. + * Checks data flow for an end graph node. */ static Verifier_Result -vf_check_end_node_data_flow( unsigned node_num, // graph node number - vf_MapVector_t *invector, // end node incoming data flow vector +vf_check_end_node_data_flow( vf_MapVector_t *invector, // end node incoming data flow vector vf_Context_t *ctex) // verifier context { bool copy; @@ -1129,27 +1117,21 @@ } // check method - if( !memcmp( method_get_name( ctex->m_method ), "", 7 ) + if( ctex->m_is_constructor && ctex->m_vtype.m_class != ctex->m_vtype.m_object ) { - if( invector->m_local->m_type != SM_UNINITIALIZED - && invector->m_local->m_vtype == ctex->m_vtype.m_class) - { - // constructor returns initialized reference of a given class - } else { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Constructor must be invoked" ); + if( invector->m_local->m_type == SM_UNINITIALIZED ) { + VERIFY_REPORT_METHOD( ctex, + "Constructor must be invoked" ); return VER_ErrorDataFlow; } } - // get first instruction - vf_Code_t *instr = &ctex->m_code[ctex->m_graph->GetNodeFirstInstr( node_num )]; + // get the end entry + vf_Node_t* node = ctex->m_graph->GetNode( ctex->m_nodeNum - 1 ); // check void return - if( !instr->m_inlen ) { + if( 0 == node->m_inMapVector.m_depth ) { if( invector->m_stack ) { if( invector->m_stack->m_type == SM_TOP ) { // no return value, empty stack - all is ok @@ -1159,32 +1141,33 @@ // no stack, no return value - all is ok return VER_OK; } - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Wrong return type in function" ); + VERIFY_REPORT_METHOD( ctex, + "Wrong return type in function" ); return VER_ErrorDataFlow; } - assert( invector->m_deep - instr->m_minstack >= 0 ); + // stack size should be greater or equal than a minimal + // stack size which is a number of words to return (0, 1 or 2) + assert( invector->m_depth - node->m_inMapVector.m_depth >= 0 ); /** * Check end-entry IN vector */ - for( index = 0, vector = &instr->m_invector[0]; - index < instr->m_inlen; - index++, vector = &instr->m_invector[index] ) + for( index = 0; + index < node->m_inMapVector.m_depth; + index++ ) { // get check entry + vector = node->m_inMapVector.m_stack + index; assert( vector->m_is_local == 0 ); + // check stack type vf_MapEntry_t *entry = invector->m_stack + index; + // check entry types Verifier_Result result = vf_check_entry_types( entry, vector, true, ©, ctex ); if( result != VER_OK ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Wrong return type in function" ); + VERIFY_REPORT_METHOD( ctex, + "Wrong return type in function" ); return result; } } @@ -1206,8 +1189,8 @@ vf_Graph_t *graph = ctex->m_graph; // skip end-entry node - if( vf_is_instruction_has_flags( &ctex->m_code[graph->GetNodeFirstInstr( node_num )], - VF_FLAG_END_ENTRY) ) + vf_Node_t* node = graph->GetNode( node_num ); + if( VF_TYPE_NODE_END_ENTRY == node->m_type ) { return VER_OK; } @@ -1242,11 +1225,9 @@ unsigned out_node = graph->GetEdgeEndNode( out_edge ); // check vectors for end-entry - if( vf_is_instruction_has_flags( - &ctex->m_code[graph->GetNodeFirstInstr( out_node )], - VF_FLAG_END_ENTRY) ) + if( VF_TYPE_NODE_END_ENTRY == graph->GetNode( out_node )->m_type ) { - Verifier_Result result = vf_check_end_node_data_flow( out_node, + Verifier_Result result = vf_check_end_node_data_flow( in_node_vector, ctex ); if( result != VER_OK ) { return result; @@ -1259,9 +1240,7 @@ if( !out_node_vector->m_maxlocal || !out_node_vector->m_maxstack ) { // node's IN vector is invalid, set it - if( vf_is_instruction_has_flags( - &ctex->m_code[graph->GetNodeFirstInstr( out_node )], - VF_FLAG_HANDLER) ) + if( VF_TYPE_NODE_HANDLER == graph->GetNode( out_node )->m_type ) { // it's exception node, create IN vector for it vf_copy_vector( in_node_vector, incoming ); @@ -1279,9 +1258,7 @@ } #endif // _VERIFY_DEBUG // node's IN vector is valid, merge them - bool is_handler = vf_is_instruction_has_flags( - &ctex->m_code[graph->GetNodeFirstInstr( out_node )], - VF_FLAG_HANDLER); + bool is_handler = VF_TYPE_NODE_HANDLER == graph->GetNode( out_node )->m_type; is_changed = vf_merge_vectors( out_node_vector, in_node_vector, is_handler, ctex ); if( is_changed ) { // node IN vector is changed, reset node OUT vector results @@ -1316,20 +1293,19 @@ } // vf_check_node_data_flow /** - * Function creates initial data flow vector for method. + * Creates input and output stack maps. */ static vf_MapVector_t* -vf_create_method_begin_vector( vf_Context_t *ctex ) // verifier context +vf_create_terminal_maps( vf_Context_t *ctex ) // verifier context { int index, count, inlen, - begin, + start, outlen; unsigned locals, maxstack; - vf_MapEntry_t *invector, - *outvector; + vf_MapEntry_t *invector; vf_MapVector_t *vector; // get method values @@ -1338,6 +1314,7 @@ // alloc memory for vector structure vector = (vf_MapVector_t*)ctex->m_graph->AllocMemory( sizeof(vf_MapVector_t) ); + // alloc memory for stack vector if( maxstack ) { vector->m_maxstack = (unsigned short)maxstack; @@ -1354,19 +1331,31 @@ // get method signature const char *descr = method_get_descriptor( ctex->m_method ); - // get method vectors + // get the end node IN vector + vf_MapVector_t* p_outvector = + ctex->m_graph->GetNodeInVector(ctex->m_nodeNum - 1); + + // get vectors sizes vf_parse_description( descr, &inlen, &outlen ); - vf_set_description_vector( descr, inlen, 0, outlen, &invector, &outvector, ctex ); + p_outvector->m_depth = outlen; + // get method vectors + vf_set_description_vector(descr, inlen, 0, outlen, &invector, + &p_outvector->m_stack, ctex); + + // cache in the context if the method is a constructor + ctex->m_is_constructor = + memcmp(method_get_name(ctex->m_method), "", 7) == 0; + // set "this" reference in local variable if( method_is_static( ctex->m_method ) ) { - begin = 0; + start = 0; } else { - begin = 1; + start = 1; // fill "this" entry const char *name = class_get_name( ctex->m_class ); vf_ValidType_t *type = vf_create_class_valid_type( name, ctex ); - if( !memcmp( method_get_name( ctex->m_method ), "", 7 ) ) { + if( ctex->m_is_constructor ) { vector->m_local->m_type = SM_UNINITIALIZED; } else { vector->m_local->m_type = SM_REF; @@ -1377,7 +1366,7 @@ } // set start vector - for( index = begin, count = 0; count < inlen; index++, count++ ) { + for( index = start, count = 0; count < inlen; index++, count++ ) { vector->m_local[index].m_type = invector[count].m_type; vector->m_local[index].m_vtype = invector[count].m_vtype; vector->m_local[index].m_is_local = 1; @@ -1385,7 +1374,6 @@ } vector->m_number = (unsigned short)index; - // FIXME - need set end entry vector return vector; } // vf_create_method_begin_vector @@ -1404,7 +1392,7 @@ graph->SetNodeMark( 0, VERIFY_START_MARK ); // enumerate graph nodes - for( unsigned index = 0; index < graph->GetNodeNumber(); index++ ) { + for( unsigned index = 0; index < graph->GetNodeCount(); index++ ) { // get node by count element unsigned node_num = graph->GetCountElementNode( index ); if( node_num == ~0U ) { @@ -1447,8 +1435,8 @@ // enumerate graph vf_enumerate_graph_node( ctex ); - // get begin vector - vf_MapVector_t *begin = vf_create_method_begin_vector( ctex ); + // get a start vector + vf_MapVector_t *start = vf_create_terminal_maps( ctex ); // create buf stack map vector (max 4 entry) vf_MapEntry_t *buf = (vf_MapEntry_t*)vf_alloc_pool_memory( ctex->m_pool, @@ -1459,14 +1447,14 @@ graph->CleanNodesMark(); // set start node IN vector - graph->SetNodeInVector( 0, begin, true ); + graph->SetNodeInVector( 0, start, true ); // check graph data flow bool need_recheck = false; unsigned count = 0; do { unsigned node = graph->GetCountElementNode( count ); - Verifier_Result result = vf_check_node_data_flow( node, begin, buf, &count, &need_recheck, ctex ); + Verifier_Result result = vf_check_node_data_flow( node, start, buf, &count, &need_recheck, ctex ); if( result != VER_OK ) { return result; }