These expressions check whether array dimensions are not negative upon creation. If negative size is detected then NegativeArraySizeException is thrown.
Signed-off-by: Tomek Grabiec <[email protected]> --- arch/x86/insn-selector_32.brg | 30 ++++++++++++++++++- include/jit/bc-offset-mapping.h | 2 - include/jit/expression.h | 7 ++++ include/vm/class.h | 2 + jit/expression.c | 28 ++++++++++++++++++ jit/object-bc.c | 22 +++++++++++-- jit/tree-printer.c | 36 ++++++++++++++++++++++- test/arch-x86/insn-selector-test_32.c | 51 --------------------------------- test/jamvm/class-stub.c | 9 ++++++ test/jit/bc-test-utils.c | 16 ++++++++++ test/jit/bc-test-utils.h | 3 +- test/jit/object-bc-test.c | 9 ++--- vm/class.c | 31 ++++++++++++++++++++ 13 files changed, 181 insertions(+), 65 deletions(-) diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg index 7b9a933..12f7e9e 100644 --- a/arch/x86/insn-selector_32.brg +++ b/arch/x86/insn-selector_32.brg @@ -729,6 +729,18 @@ reg: EXPR_NEW select_exception_test(s, tree); } +reg: EXPR_ARRAY_SIZE_CHECK(reg) +{ + struct var_info *size; + + size = state->left->reg1; + state->reg1 = size; + + select_insn(s, tree, reg_insn(INSN_PUSH_REG, size)); + select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) array_size_check)); + method_args_cleanup(s, tree, 1); +} + reg: EXPR_NEWARRAY(reg) { struct var_info *var, *size; @@ -778,12 +790,27 @@ reg: EXPR_NULL_CHECK(EXPR_LOCAL) select_insn(s, tree, membase_reg_insn(INSN_TEST_MEMBASE_REG, reg, 0, reg)); } +arg: EXPR_MULTIARRAY_SIZE_CHECK(arg) +{ + struct expression *expr; + int dimensions; + + expr = to_expr(tree); + dimensions = nr_args(to_expr(expr->size_expr)); + + select_insn(s, tree, imm_insn(INSN_PUSH_IMM, dimensions)); + select_insn(s, tree, rel_insn(INSN_CALL_REL, + (unsigned long) multiarray_size_check)); + method_args_cleanup(s, tree, 1); +} + reg: EXPR_MULTIANEWARRAY(arg) { struct var_info *var; struct var_info *stack_ptr; unsigned int dimension; struct expression *expr; + struct expression *size_check; expr = to_expr(tree); @@ -792,7 +819,8 @@ reg: EXPR_MULTIANEWARRAY(arg) stack_ptr = get_fixed_var(s->b_parent, REG_ESP); - dimension = nr_args(to_expr(expr->multianewarray_dimensions)); + size_check = to_expr(expr->multianewarray_dimensions); + dimension = nr_args(to_expr(size_check->size_expr)); select_insn(s, tree, reg_insn(INSN_PUSH_REG, stack_ptr)); select_insn(s, tree, imm_insn(INSN_PUSH_IMM, dimension)); diff --git a/include/jit/bc-offset-mapping.h b/include/jit/bc-offset-mapping.h index 21ec6df..c47ea51 100644 --- a/include/jit/bc-offset-mapping.h +++ b/include/jit/bc-offset-mapping.h @@ -11,8 +11,6 @@ unsigned long native_ptr_to_bytecode_offset(struct compilation_unit *cu, unsigned char *native_ptr); void print_bytecode_offset(unsigned long bc_offset, struct string *str); - -unsigned long tree_bytecode_offset(struct tree_node *node); void tree_patch_bc_offset(struct tree_node *node, unsigned long bc_offset); bool all_insn_have_bytecode_offset(struct compilation_unit *cu); diff --git a/include/jit/expression.h b/include/jit/expression.h index 09943fd..43b41c0 100644 --- a/include/jit/expression.h +++ b/include/jit/expression.h @@ -33,6 +33,8 @@ enum expression_type { EXPR_INSTANCEOF, EXPR_EXCEPTION_REF, EXPR_NULL_CHECK, + EXPR_ARRAY_SIZE_CHECK, + EXPR_MULTIARRAY_SIZE_CHECK, EXPR_LAST, /* Not a real type. Keep this last. */ }; @@ -230,6 +232,9 @@ struct expression { /* EXPR_NULL_CHECK is used to assure that NullPointerException will be thrown if reference is null. */ struct tree_node *null_check_ref; + + /* EXPR_ARRAY_SIZE_CHECK and EXPR_MULTIARRAY_SIZE_CHECK */ + struct tree_node *size_expr; }; }; @@ -282,6 +287,8 @@ struct expression *arraylength_expr(struct expression *); struct expression *instanceof_expr(struct expression *, struct object *); struct expression *exception_ref_expr(void); struct expression *null_check_expr(struct expression *); +struct expression *array_size_check_expr(struct expression *); +struct expression *multiarray_size_check_expr(struct expression *); unsigned long nr_args(struct expression *); int expr_nr_kids(struct expression *); diff --git a/include/vm/class.h b/include/vm/class.h index d78218b..6dd5b38 100644 --- a/include/vm/class.h +++ b/include/vm/class.h @@ -10,5 +10,7 @@ void check_array(struct object *obj, unsigned int index); void check_cast(struct object *obj, struct object *type); void array_store_check(struct object *arrayref, struct object *obj); void array_store_check_vmtype(struct object *arrayref, enum vm_type vm_type); +void array_size_check(int size); +void multiarray_size_check(int n, ...); #endif /* __CLASS_H */ diff --git a/jit/expression.c b/jit/expression.c index 4905924..8e4d736 100644 --- a/jit/expression.c +++ b/jit/expression.c @@ -33,6 +33,8 @@ int expr_nr_kids(struct expression *expr) case EXPR_ARRAYLENGTH: case EXPR_INSTANCEOF: case EXPR_NULL_CHECK: + case EXPR_ARRAY_SIZE_CHECK: + case EXPR_MULTIARRAY_SIZE_CHECK: return 1; case EXPR_VALUE: case EXPR_FVALUE: @@ -344,3 +346,29 @@ struct expression *null_check_expr(struct expression *ref) return expr; } + +struct expression *array_size_check_expr(struct expression *size) +{ + struct expression *expr; + + expr = alloc_expression(EXPR_ARRAY_SIZE_CHECK, J_INT); + if (!expr) + return NULL; + + expr->size_expr = &size->node; + + return expr; +} + +struct expression *multiarray_size_check_expr(struct expression *dimensions) +{ + struct expression *expr; + + expr = alloc_expression(EXPR_MULTIARRAY_SIZE_CHECK, J_VOID); + if (!expr) + return NULL; + + expr->size_expr = &dimensions->node; + + return expr; +} diff --git a/jit/object-bc.c b/jit/object-bc.c index a97a85f..5d39393 100644 --- a/jit/object-bc.c +++ b/jit/object-bc.c @@ -363,12 +363,17 @@ int convert_new(struct parse_context *ctx) int convert_newarray(struct parse_context *ctx) { struct expression *size, *arrayref; + struct expression *size_check; unsigned long type; size = stack_pop(ctx->bb->mimic_stack); type = bytecode_read_u8(ctx->buffer); - arrayref = newarray_expr(type, size); + size_check = array_size_check_expr(size); + if (!size_check) + return -ENOMEM; + + arrayref = newarray_expr(type, size_check); if (!arrayref) return -ENOMEM; @@ -379,6 +384,7 @@ int convert_newarray(struct parse_context *ctx) int convert_anewarray(struct parse_context *ctx) { + struct expression *size_check; struct expression *size,*arrayref; unsigned long type_idx; struct object *class, *arrayclass; @@ -394,7 +400,11 @@ int convert_anewarray(struct parse_context *ctx) if (!arrayclass) return -EINVAL; - arrayref = anewarray_expr(arrayclass,size); + size_check = array_size_check_expr(size); + if (!size_check) + return -ENOMEM; + + arrayref = anewarray_expr(arrayclass, size_check); if (!arrayref) return -ENOMEM; @@ -405,6 +415,7 @@ int convert_anewarray(struct parse_context *ctx) int convert_multianewarray(struct parse_context *ctx) { + struct expression *size_check; struct expression *arrayref; struct expression *args_list; unsigned long type_idx; @@ -423,10 +434,13 @@ int convert_multianewarray(struct parse_context *ctx) return -ENOMEM; args_list = convert_args(ctx->bb->mimic_stack, dimension); - arrayref->multianewarray_dimensions = &args_list->node; - if (!arrayref->multianewarray_dimensions) + + size_check = multiarray_size_check_expr(args_list); + if (!size_check) return -ENOMEM; + arrayref->multianewarray_dimensions = &size_check->node; + convert_expression(ctx, arrayref); return 0; diff --git a/jit/tree-printer.c b/jit/tree-printer.c index 49c113b..c96c87b 100644 --- a/jit/tree-printer.c +++ b/jit/tree-printer.c @@ -749,6 +749,37 @@ static int print_null_check_expr(int lvl, struct string *str, return err; } +static int print_array_size_check_expr(int lvl, struct string *str, + struct expression *expr) +{ + int err; + + err = append_formatted(lvl, str, "ARRAY_SIZE_CHECK:\n"); + if (err) + goto out; + + err = append_tree_attr(lvl + 1, str, "size", expr->size_expr); + + out: + return err; +} + +static int print_multiarray_size_check_expr(int lvl, struct string *str, + struct expression *expr) +{ + int err; + + err = append_formatted(lvl, str, "MULTIARRAY_SIZE_CHECK:\n"); + if (err) + goto out; + + err = append_tree_attr(lvl + 1, str, "dimension list", + expr->size_expr); + + out: + return err; +} + typedef int (*print_expr_fn) (int, struct string * str, struct expression *); static print_expr_fn expr_printers[] = { @@ -774,7 +805,10 @@ static print_expr_fn expr_printers[] = { [EXPR_ARRAYLENGTH] = print_arraylength_expr, [EXPR_INSTANCEOF] = print_instanceof_expr, [EXPR_EXCEPTION_REF] = print_exception_ref_expr, - [EXPR_NULL_CHECK] = print_null_check_expr + [EXPR_NULL_CHECK] = print_null_check_expr, + [EXPR_ARRAY_SIZE_CHECK] = print_array_size_check_expr, + [EXPR_MULTIARRAY_SIZE_CHECK] = print_multiarray_size_check_expr + }; static int print_expr(int lvl, struct tree_node *root, struct string *str) diff --git a/test/arch-x86/insn-selector-test_32.c b/test/arch-x86/insn-selector-test_32.c index 319b63a..5a9cdf4 100644 --- a/test/arch-x86/insn-selector-test_32.c +++ b/test/arch-x86/insn-selector-test_32.c @@ -1333,57 +1333,6 @@ void test_select_anewarray(void) free_compilation_unit(cu); } -void test_select_multianewarray(void) -{ - struct object *instance_class; - struct compilation_unit *cu; - struct expression *expr, *args_list_expression; - struct statement *stmt; - struct basic_block *bb; - struct insn *insn; - - instance_class = new_class(); - - args_list_expression = args_list_expr(arg_expr(value_expr(J_INT, 0x02)), - arg_expr(value_expr(J_INT, 0xff))); - - expr = multianewarray_expr(instance_class); - expr->multianewarray_dimensions = &args_list_expression->node; - - stmt = alloc_statement(STMT_EXPRESSION); - stmt->expression = &expr->node; - - cu = alloc_compilation_unit(&method); - bb = get_basic_block(cu, 0, 1); - bb_add_stmt(bb, stmt); - - select_instructions(bb->b_parent); - - insn = list_first_entry(&bb->insn_list, struct insn, insn_list_node); - assert_imm_insn(INSN_PUSH_IMM, 0x02, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_imm_insn(INSN_PUSH_IMM, 0xff, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_reg_insn(INSN_PUSH_REG, REG_ESP, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_imm_insn(INSN_PUSH_IMM, 0x02, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_imm_insn(INSN_PUSH_IMM, (unsigned long) instance_class, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_rel_insn(INSN_CALL_REL, (unsigned long) allocMultiArray, insn); - - insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node); - assert_imm_reg_insn(INSN_ADD_IMM_REG, 20, REG_ESP, insn); - - free(instance_class); - free_compilation_unit(cu); -} - void test_select_arraylength(void) { struct object *instance_class; diff --git a/test/jamvm/class-stub.c b/test/jamvm/class-stub.c index 0ef5576..83aac13 100644 --- a/test/jamvm/class-stub.c +++ b/test/jamvm/class-stub.c @@ -42,3 +42,12 @@ void array_store_check(struct object *arrayref, struct object *obj) void array_store_check_vmtype(struct object *arrayref, enum vm_type vm_type) { } + +void array_size_check(int size) +{ +} + +void multiarray_size_check(int n, ...) +{ +} + diff --git a/test/jit/bc-test-utils.c b/test/jit/bc-test-utils.c index 54375f3..c4e973e 100644 --- a/test/jit/bc-test-utils.c +++ b/test/jit/bc-test-utils.c @@ -5,6 +5,7 @@ #include <jit/compilation-unit.h> #include <jit/basic-block.h> #include <bc-test-utils.h> +#include <args-test-utils.h> #include <jit/tree-node.h> #include <jit/expression.h> #include <jit/statement.h> @@ -210,6 +211,21 @@ void assert_invoke_expr(enum vm_type expected_type, assert_ptr_equals(expected_method, expr->target_method); } +void assert_array_size_check_expr(struct expression *expected, + struct expression *actual) +{ + assert_int_equals(EXPR_ARRAY_SIZE_CHECK, expr_type(actual)); + assert_ptr_equals(&expected->node, actual->size_expr); +} + +void assert_multiarray_size_check_expr(struct expression **expected_args, + int nr_args, + struct expression *actual) +{ + assert_int_equals(EXPR_MULTIARRAY_SIZE_CHECK, expr_type(actual)); + assert_args(expected_args, nr_args, to_expr(actual->size_expr)); +} + void assert_store_stmt(struct statement *stmt) { assert_int_equals(STMT_STORE, stmt_type(stmt)); diff --git a/test/jit/bc-test-utils.h b/test/jit/bc-test-utils.h index 76324cc..514b09a 100644 --- a/test/jit/bc-test-utils.h +++ b/test/jit/bc-test-utils.h @@ -36,7 +36,8 @@ void assert_class_field_expr(enum vm_type, struct fieldblock *, struct tree_node void assert_instance_field_expr(enum vm_type, struct fieldblock *, struct expression *, struct tree_node *); void assert_invoke_expr(enum vm_type, struct methodblock *, struct tree_node *); - +void assert_array_size_check_expr(struct expression *, struct expression *); +void assert_multiarray_size_check_expr(struct expression **, int, struct expression *); void assert_store_stmt(struct statement *); void assert_array_store_check_stmt(struct statement *, struct expression *, struct tree_node *); void assert_return_stmt(struct expression *, struct statement *); diff --git a/test/jit/object-bc-test.c b/test/jit/object-bc-test.c index d5c8976..ad04680 100644 --- a/test/jit/object-bc-test.c +++ b/test/jit/object-bc-test.c @@ -455,7 +455,7 @@ void test_convert_anewarray(void) assert_int_equals(EXPR_ANEWARRAY, expr_type(arrayref)); assert_int_equals(J_REFERENCE, arrayref->vm_type); - assert_ptr_equals(size, to_expr(arrayref->anewarray_size)); + assert_array_size_check_expr(size, to_expr(arrayref->anewarray_size)); /* * Free the struct object returned from findArrayClassFromClassLoader() @@ -488,7 +488,7 @@ void test_convert_newarray(void) arrayref = stack_pop(bb->mimic_stack); assert_int_equals(EXPR_NEWARRAY, expr_type(arrayref)); assert_int_equals(J_REFERENCE, arrayref->vm_type); - assert_ptr_equals(size, to_expr(arrayref->array_size)); + assert_array_size_check_expr(size, to_expr(arrayref->array_size)); assert_int_equals(T_INT, arrayref->array_type); expr_put(arrayref); @@ -502,7 +502,6 @@ void test_convert_multianewarray(void) unsigned char code[] = { OPC_MULTIANEWARRAY, 0x00, 0x00, dimension }; struct expression *arrayref; struct expression *args_count[dimension]; - struct expression *actual_args; struct basic_block *bb; struct methodblock method = { .jit_code = code, @@ -522,8 +521,8 @@ void test_convert_multianewarray(void) assert_int_equals(J_REFERENCE, arrayref->vm_type); assert_ptr_equals(instance_class, arrayref->multianewarray_ref_type); - actual_args = to_expr(arrayref->multianewarray_dimensions); - assert_args(args_count, dimension, actual_args); + assert_multiarray_size_check_expr(args_count, dimension, + to_expr(arrayref->multianewarray_dimensions)); assert_true(stack_is_empty(bb->mimic_stack)); diff --git a/vm/class.c b/vm/class.c index 3748f75..d8d1fc9 100644 --- a/vm/class.c +++ b/vm/class.c @@ -197,3 +197,34 @@ void check_cast(struct object *obj, struct object *type) die("%s: error %d", __func__, err); } + +void array_size_check(int size) +{ + if (size < 0) { + signal_new_exception( + "java/lang/NegativeArraySizeException", NULL); + throw_from_native(sizeof(int)); + } +} + +void multiarray_size_check(int n, ...) +{ + va_list ap; + int i; + + va_start(ap, n); + + for (i = 0; i < n; i++) { + if (va_arg(ap, int) >= 0) + continue; + + signal_new_exception("java/lang/NegativeArraySizeException", + NULL); + va_end(ap); + throw_from_native(sizeof(int) * (n + 1)); + return; + } + + va_end(ap); + return; +} -- 1.6.0.6 ------------------------------------------------------------------------------ Crystal Reports - New Free Runtime and 30 Day Trial Check out the new simplified licensing option that enables unlimited royalty-free distribution of the report engine for externally facing server and web deployment. http://p.sf.net/sfu/businessobjects _______________________________________________ Jatovm-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/jatovm-devel
