blob: 7d27b6bab0903a4556b8c785e6b414a70dd256a6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "verifier.h"
#include "../java5/context_5.h"
#include "../java6/context_6.h"
#ifndef _NDEBUG
#include "class_interface.h"
#endif
#include "open/vm_class_manipulation.h"
#include "open/vm_method_access.h"
#include "open/vm_class_loading.h"
/**
* Provides initial java-5 verification of class.
*
* If when verifying the class a check of type "class A must be assignable to class B" needs to be done
* and either A or B is not loaded at the moment then a constraint
* "class A must be assignable to class B" is recorded into the classloader's data
*/
vf_Result
vf_verify5_class(Class_Handle klass, unsigned verifyAll, char** error)
{
int index;
vf_Result result = VF_OK;
// Create context
SharedClasswideData classwide(klass);
vf_Context_5 context(classwide);
// Verify method
for( index = 0; index < class_get_method_number( klass ); index++ ) {
result = context.verify_method(class_get_method( klass, index ));
if (result != VF_OK) {
vf_create_error_message(class_get_method(klass, index), context, error);
break;
}
}
/**
* Set method constraints
*/
context.set_class_constraints();
return result;
} // vf_verify5_class
/**
* Provides initial java-6 verification of class.
*
* If when verifying the class a check of type "class A must be assignable to class B" needs to be done
* and either A or B is not loaded at the moment then a constraint
* "class A must be assignable to class B" is recorded into the classloader's data
*/
vf_Result
vf_verify6_class(Class_Handle klass, unsigned verifyAll, char **error )
{
int index;
vf_Result result = VF_OK;
// Create contexts
SharedClasswideData classwide(klass);
vf_Context_5 context5(classwide);
vf_Context_6 context6(classwide);
bool skip_java6_verification_attempt = false;
// Verify method
for( index = 0; index < class_get_method_number( klass ); index++ ) {
Method_Handle method = class_get_method( klass, index );
//try Java6 verifying (using StackMapTable attribute)
if( !skip_java6_verification_attempt || method_get_stackmaptable(method) ) {
result = context6.verify_method(method);
if (result != VF_OK) {
//skip Java6 attempts for further methods unless they have StackMapTable
skip_java6_verification_attempt = true;
if (result == VF_ErrorStackmap) {
//corrupted StackMapTable ==> throw an Error?
vf_create_error_message(method, context6, error);
return result;
}
}
}
if( result != VF_OK ) {
//try Java5 verifying
result = context5.verify_method(method);
if (result != VF_OK) {
vf_create_error_message(method, context5, error);
return result;
}
}
}
/**
* Set method constraints
*/
context5.set_class_constraints();
return result;
} // vf_verify6_class
/**
* Provides initial verification of a class.
*
* If when verifying the class a check of type "class A must be assignable to class B" needs to be done
* and either A or B is not loaded at the moment then a constraint
* "class A must be assignable to class B" is recorded into the classloader's data
*/
vf_Result
vf_verify_class( Class_Handle klass, unsigned verifyAll, char **error ) {
return class_get_version(klass) >= 50 ? vf_verify6_class(klass, verifyAll, error) : vf_verify5_class(klass, verifyAll, error);
}
/**
* Function verifies all the constraints "class A must be assignable to class B"
* that are recorded into the classloader for the given class
* If some class is not loaded yet -- load it now
*/
vf_Result
vf_verify_class_constraints(Class_Handle klass, unsigned verifyAll, char** error)
{
// get class loader of current class
Class_Loader_Handle class_loader = class_get_class_loader(klass);
// get class loader verify data
vf_ClassLoaderData_t *cl_data =
(vf_ClassLoaderData_t*)class_loader_get_verifier_data_ptr(class_loader);
// check class loader data
if( cl_data == NULL ) {
// no constraint data
return VF_OK;
}
// get class hash and memory pool
vf_Hash *hash = cl_data->hash;
// get constraints for class
vf_HashEntry_t *hash_entry = hash->Lookup( class_get_name( klass ) );
if( !hash_entry || !hash_entry->data_ptr ) {
// no constraint data
return VF_OK;
}
// check method constraints
vf_TypeConstraint *constraint = (vf_TypeConstraint*)hash_entry->data_ptr;
for( ; constraint; constraint = constraint->next )
{
vf_Result result = vf_force_check_constraint( klass, constraint );
if( result != VF_OK ) {
vf_create_error_message(klass, constraint, error);
return result;
}
}
return VF_OK;
} // vf_verify_method_constraints
/**
* Releases verify data in class loader (used to store constraints)
*/
void
vf_release_verify_data( void *data )
{
vf_ClassLoaderData_t *cl_data = (vf_ClassLoaderData_t*)data;
delete cl_data->string;
delete cl_data->hash;
delete cl_data->pool;
} // vf_release_verify_data
#ifndef _NDEBUG
void method_remove_exc_handler( Method_Handle method, unsigned short idx ) {
//unimplemented, needed for stack map re-computation testing
assert(0);
}
void method_modify_exc_handler_info( Method_Handle method, unsigned short idx,
unsigned short start_pc, unsigned short end_pc,
unsigned short handler_pc, unsigned short handler_cp_index )
{
//unimplemented
assert(0);
}
unsigned short class_cp_get_class_entry(Class_Handle k_class, const char* name) {
for( unsigned short i = 1; i < class_cp_get_size( k_class ); i++ ) {
if( class_cp_get_tag( k_class, i ) == _CONSTANT_Class ) {
unsigned short name_idx = class_cp_get_class_name_index(k_class, i);
const char* cp_name = class_cp_get_utf8_bytes( k_class, name_idx );
if( !strcmp(name, cp_name) ) return i;
}
}
return 0;
}
#endif