--- old/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Thu Jul 5 14:10:17 2012 +++ new/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Thu Jul 5 14:10:17 2012 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -688,8 +688,7 @@ if (sde == null) { String extension = null; if (saKlass instanceof InstanceKlass) { - Symbol sdeSym = ((InstanceKlass)saKlass).getSourceDebugExtension(); - extension = (sdeSym != null)? sdeSym.asString() : null; + extension = ((InstanceKlass)saKlass).getSourceDebugExtension(); } if (extension == null) { sde = NO_SDE_INFO_MARK; --- old/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Thu Jul 5 14:10:19 2012 +++ new/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Thu Jul 5 14:10:18 2012 @@ -342,7 +342,7 @@ public Oop getProtectionDomain() { return protectionDomain.getValue(this); } public ObjArray getSigners() { return (ObjArray) signers.getValue(this); } public Symbol getSourceFileName() { return getSymbol(sourceFileName); } - public Symbol getSourceDebugExtension(){ return getSymbol(sourceDebugExtension); } + public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getHandle())); } public TypeArray getInnerClasses() { return (TypeArray) innerClasses.getValue(this); } public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); } --- old/src/share/vm/classfile/classFileParser.cpp Thu Jul 5 14:10:20 2012 +++ new/src/share/vm/classfile/classFileParser.cpp Thu Jul 5 14:10:19 2012 @@ -2337,12 +2337,7 @@ // Don't bother storing it if there is no way to retrieve it if (JvmtiExport::can_get_source_debug_extension()) { - // Optimistically assume that only 1 byte UTF format is used - // (common case) - TempNewSymbol sde_symbol = SymbolTable::new_symbol((const char*)sde_buffer, length, CHECK); - k->set_source_debug_extension(sde_symbol); - // Note that set_source_debug_extension() increments the reference count - // for its copy of the Symbol*, so use a TempNewSymbol here. + k->set_source_debug_extension((char*)sde_buffer, length); } // Got utf8 string, set stream position forward cfs->skip_u1(length, CHECK); --- old/src/share/vm/oops/instanceKlass.cpp Thu Jul 5 14:10:21 2012 +++ new/src/share/vm/oops/instanceKlass.cpp Thu Jul 5 14:10:21 2012 @@ -847,7 +847,6 @@ Klass::shared_symbols_iterate(closure); closure->do_symbol(&_generic_signature); closure->do_symbol(&_source_file_name); - closure->do_symbol(&_source_debug_extension); for (JavaFieldStream fs(this); !fs.done(); fs.next()) { int name_index = fs.name_index(); @@ -1944,9 +1943,10 @@ // class can't be referenced anymore). if (_array_name != NULL) _array_name->decrement_refcount(); if (_source_file_name != NULL) _source_file_name->decrement_refcount(); - if (_source_debug_extension != NULL) _source_debug_extension->decrement_refcount(); // walk constant pool and decrement symbol reference counts _constants->unreference_symbols(); + + if (_source_debug_extension != NULL) FREE_C_HEAP_ARRAY(u1, _source_debug_extension, mtClass); } void instanceKlass::set_source_file_name(Symbol* n) { @@ -1954,9 +1954,22 @@ if (_source_file_name != NULL) _source_file_name->increment_refcount(); } -void instanceKlass::set_source_debug_extension(Symbol* n) { - _source_debug_extension = n; - if (_source_debug_extension != NULL) _source_debug_extension->increment_refcount(); +void instanceKlass::set_source_debug_extension(char* array, int length) { + if (array == NULL) { + _source_debug_extension = NULL; + } else { + // Adding one to the attribute length in order to store a null terminator + // character could cause an overflow because the attribute length is + // already coded with an u4 in the classfile, but in practice, it's + // unlikely to happen. + assert((length+1) > length, "Overflow checking"); + char* sde = NEW_C_HEAP_ARRAY(char, (length + 1), mtClass); + for (int i = 0; i < length; i++) { + sde[i] = array[i]; + } + sde[length] = '\0'; + _source_debug_extension = (char*)sde; + } } address instanceKlass::static_field_addr(int offset) { --- old/src/share/vm/oops/instanceKlass.hpp Thu Jul 5 14:10:23 2012 +++ new/src/share/vm/oops/instanceKlass.hpp Thu Jul 5 14:10:22 2012 @@ -226,7 +226,9 @@ // Name of source file containing this klass, NULL if not specified. Symbol* _source_file_name; // the source debug extension for this klass, NULL if not specified. - Symbol* _source_debug_extension; + // Specified as UTF-8 string without terminating zero byte in the classfile, + // it is stored in the instanceklass as a NULL-terminated UTF-8 string + char* _source_debug_extension; // Generic signature, or null if none. Symbol* _generic_signature; // Array name derived from this class which needs unreferencing @@ -542,8 +544,8 @@ void set_major_version(u2 major_version) { _major_version = major_version; } // source debug extension - Symbol* source_debug_extension() const { return _source_debug_extension; } - void set_source_debug_extension(Symbol* n); + char* source_debug_extension() const { return _source_debug_extension; } + void set_source_debug_extension(char* array, int length); // symbol unloading support (refcount already added) Symbol* array_name() { return _array_name; } --- old/src/share/vm/oops/instanceKlassKlass.cpp Thu Jul 5 14:10:24 2012 +++ new/src/share/vm/oops/instanceKlassKlass.cpp Thu Jul 5 14:10:24 2012 @@ -421,8 +421,7 @@ ik->set_protection_domain(NULL); ik->set_signers(NULL); ik->set_source_file_name(NULL); - ik->set_source_debug_extension(NULL); - ik->set_source_debug_extension(NULL); + ik->set_source_debug_extension(NULL, 0); ik->set_array_name(NULL); ik->set_inner_classes(NULL); ik->set_static_oop_field_count(0); @@ -531,7 +530,7 @@ } if (ik->source_debug_extension() != NULL) { st->print(BULLET"source debug extension: "); - ik->source_debug_extension()->print_value_on(st); + st->print_cr("%s", ik->source_debug_extension()); st->cr(); } --- old/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Thu Jul 5 14:10:25 2012 +++ new/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Thu Jul 5 14:10:25 2012 @@ -268,14 +268,18 @@ // JSR45| SourceDebugExtension_attribute { // JSR45| u2 attribute_name_index; // JSR45| u4 attribute_length; -// JSR45| u2 sourcefile_index; +// JSR45| u1 debug_extension[attribute_length]; // JSR45| } void JvmtiClassFileReconstituter::write_source_debug_extension_attribute() { assert(ikh()->source_debug_extension() != NULL, "caller must check"); write_attribute_name_index("SourceDebugExtension"); - write_u4(2); // always length 2 - write_u2(symbol_to_cpool_index(ikh()->source_debug_extension())); + int len = (int)strlen(ikh()->source_debug_extension()); + write_u4(len); + u1* ext = (u1*)ikh()->source_debug_extension(); + for (int i=0; ioop_is_instance()) { return JVMTI_ERROR_ABSENT_INFORMATION; } - Symbol* sdeOop = instanceKlass::cast(k)->source_debug_extension(); - NULL_CHECK(sdeOop, JVMTI_ERROR_ABSENT_INFORMATION); + char* sde = instanceKlass::cast(k)->source_debug_extension(); + NULL_CHECK(sde, JVMTI_ERROR_ABSENT_INFORMATION); { - JavaThread* current_thread = JavaThread::current(); - ResourceMark rm(current_thread); - const char* sdecp = (const char*) sdeOop->as_C_string(); - *source_debug_extension_ptr = (char *) jvmtiMalloc(strlen(sdecp)+1); - strcpy(*source_debug_extension_ptr, sdecp); + *source_debug_extension_ptr = (char *) jvmtiMalloc(strlen(sde)+1); + strcpy(*source_debug_extension_ptr, sde); } } --- old/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jul 5 14:10:28 2012 +++ new/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jul 5 14:10:28 2012 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3236,7 +3236,9 @@ // Copy the "source debug extension" attribute from new class version the_class->set_source_debug_extension( - scratch_class->source_debug_extension()); + scratch_class->source_debug_extension(), + scratch_class->source_debug_extension() == NULL ? 0 : + (int)strlen(scratch_class->source_debug_extension())); // Use of javac -g could be different in the old and the new if (scratch_class->access_flags().has_localvariable_table() != --- old/src/share/vm/runtime/vmStructs.cpp Thu Jul 5 14:10:29 2012 +++ new/src/share/vm/runtime/vmStructs.cpp Thu Jul 5 14:10:29 2012 @@ -308,7 +308,7 @@ nonstatic_field(instanceKlass, _protection_domain, oop) \ nonstatic_field(instanceKlass, _signers, objArrayOop) \ nonstatic_field(instanceKlass, _source_file_name, Symbol*) \ - nonstatic_field(instanceKlass, _source_debug_extension, Symbol*) \ + nonstatic_field(instanceKlass, _source_debug_extension, char*) \ nonstatic_field(instanceKlass, _inner_classes, typeArrayOop) \ nonstatic_field(instanceKlass, _nonstatic_field_size, int) \ nonstatic_field(instanceKlass, _static_field_size, int) \ --- /dev/null Thu Jul 5 14:10:31 2012 +++ new/test/runtime/6294277/SourceDebugExtension.java Thu Jul 5 14:10:31 2012 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6294277 + * @summary java -Xdebug crashes on SourceDebugExtension attribute larger than 64K + */ +import java.io.*; + +public class SourceDebugExtension extends ClassLoader +{ + static final int attrSize = 68000; + static byte[] header = { +(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, (byte)0x00, (byte)0x00, (byte)0x00, +(byte)0x32, (byte)0x00, (byte)0x1e, (byte)0x0a, (byte)0x00, (byte)0x06, (byte)0x00, +(byte)0x0f, (byte)0x09, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x11, (byte)0x08, +(byte)0x00, (byte)0x12, (byte)0x0a, (byte)0x00, (byte)0x13, (byte)0x00, (byte)0x14, +(byte)0x07, (byte)0x00, (byte)0x15, (byte)0x07, (byte)0x00, (byte)0x16, (byte)0x01, +(byte)0x00, (byte)0x06, (byte)0x3c, (byte)0x69, (byte)0x6e, (byte)0x69, (byte)0x74, +(byte)0x3e, (byte)0x01, (byte)0x00, (byte)0x03, (byte)0x28, (byte)0x29, (byte)0x56, +(byte)0x01, (byte)0x00, (byte)0x04, (byte)0x43, (byte)0x6f, (byte)0x64, (byte)0x65, +(byte)0x01, (byte)0x00, (byte)0x0f, (byte)0x4c, (byte)0x69, (byte)0x6e, (byte)0x65, +(byte)0x4e, (byte)0x75, (byte)0x6d, (byte)0x62, (byte)0x65, (byte)0x72, (byte)0x54, +(byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0x01, (byte)0x00, (byte)0x04, +(byte)0x6d, (byte)0x61, (byte)0x69, (byte)0x6e, (byte)0x01, (byte)0x00, (byte)0x16, +(byte)0x28, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, +(byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, +(byte)0x74, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x67, (byte)0x3b, (byte)0x29, +(byte)0x56, (byte)0x01, (byte)0x00, (byte)0x0a, (byte)0x53, (byte)0x6f, (byte)0x75, +(byte)0x72, (byte)0x63, (byte)0x65, (byte)0x46, (byte)0x69, (byte)0x6c, (byte)0x65, +(byte)0x01, (byte)0x00, (byte)0x0d, (byte)0x54, (byte)0x65, (byte)0x73, (byte)0x74, +(byte)0x50, (byte)0x72, (byte)0x6f, (byte)0x67, (byte)0x2e, (byte)0x6a, (byte)0x61, +(byte)0x76, (byte)0x61, (byte)0x0c, (byte)0x00, (byte)0x07, (byte)0x00, (byte)0x08, +(byte)0x07, (byte)0x00, (byte)0x17, (byte)0x0c, (byte)0x00, (byte)0x18, (byte)0x00, +(byte)0x19, (byte)0x01, (byte)0x00, (byte)0x34, (byte)0x54, (byte)0x65, (byte)0x73, +(byte)0x74, (byte)0x20, (byte)0x70, (byte)0x72, (byte)0x6f, (byte)0x67, (byte)0x72, +(byte)0x61, (byte)0x6d, (byte)0x20, (byte)0x66, (byte)0x6f, (byte)0x72, (byte)0x20, +(byte)0x62, (byte)0x69, (byte)0x67, (byte)0x20, (byte)0x53, (byte)0x6f, (byte)0x75, +(byte)0x72, (byte)0x63, (byte)0x65, (byte)0x44, (byte)0x65, (byte)0x62, (byte)0x75, +(byte)0x67, (byte)0x45, (byte)0x78, (byte)0x74, (byte)0x65, (byte)0x6e, (byte)0x73, +(byte)0x69, (byte)0x6f, (byte)0x6e, (byte)0x20, (byte)0x61, (byte)0x74, (byte)0x74, +(byte)0x72, (byte)0x69, (byte)0x62, (byte)0x75, (byte)0x74, (byte)0x65, (byte)0x73, +(byte)0x07, (byte)0x00, (byte)0x1a, (byte)0x0c, (byte)0x00, (byte)0x1b, (byte)0x00, +(byte)0x1c, (byte)0x01, (byte)0x00, (byte)0x08, (byte)0x54, (byte)0x65, (byte)0x73, +(byte)0x74, (byte)0x50, (byte)0x72, (byte)0x6f, (byte)0x67, (byte)0x01, (byte)0x00, +(byte)0x10, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, +(byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x4f, (byte)0x62, (byte)0x6a, +(byte)0x65, (byte)0x63, (byte)0x74, (byte)0x01, (byte)0x00, (byte)0x10, (byte)0x6a, +(byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, +(byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x79, (byte)0x73, (byte)0x74, (byte)0x65, +(byte)0x6d, (byte)0x01, (byte)0x00, (byte)0x03, (byte)0x6f, (byte)0x75, (byte)0x74, +(byte)0x01, (byte)0x00, (byte)0x15, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, +(byte)0x61, (byte)0x2f, (byte)0x69, (byte)0x6f, (byte)0x2f, (byte)0x50, (byte)0x72, +(byte)0x69, (byte)0x6e, (byte)0x74, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x65, +(byte)0x61, (byte)0x6d, (byte)0x3b, (byte)0x01, (byte)0x00, (byte)0x13, (byte)0x6a, +(byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x69, (byte)0x6f, (byte)0x2f, +(byte)0x50, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x74, (byte)0x53, (byte)0x74, +(byte)0x72, (byte)0x65, (byte)0x61, (byte)0x6d, (byte)0x01, (byte)0x00, (byte)0x07, +(byte)0x70, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x74, (byte)0x6c, (byte)0x6e, +(byte)0x01, (byte)0x00, (byte)0x15, (byte)0x28, (byte)0x4c, (byte)0x6a, (byte)0x61, +(byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, +(byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x67, +(byte)0x3b, (byte)0x29, (byte)0x56, (byte)0x01, (byte)0x00, (byte)0x14, (byte)0x53, +(byte)0x6f, (byte)0x75, (byte)0x72, (byte)0x63, (byte)0x65, (byte)0x44, (byte)0x65, +(byte)0x62, (byte)0x75, (byte)0x67, (byte)0x45, (byte)0x78, (byte)0x74, (byte)0x65, +(byte)0x6e, (byte)0x73, (byte)0x69, (byte)0x6f, (byte)0x6e, (byte)0x00, (byte)0x21, +(byte)0x00, (byte)0x05, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x00, (byte)0x00, +(byte)0x00, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x07, +(byte)0x00, (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, (byte)0x00, +(byte)0x00, (byte)0x00, (byte)0x1d, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, +(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x2a, (byte)0xb7, (byte)0x00, +(byte)0x01, (byte)0xb1, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, +(byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x00, (byte)0x01, +(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, (byte)0x00, +(byte)0x0b, (byte)0x00, (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x09, +(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x25, (byte)0x00, (byte)0x02, (byte)0x00, +(byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x09, (byte)0xb2, (byte)0x00, +(byte)0x02, (byte)0x12, (byte)0x03, (byte)0xb6, (byte)0x00, (byte)0x04, (byte)0xb1, +(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x0a, (byte)0x00, +(byte)0x00, (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x02, (byte)0x00, (byte)0x00, +(byte)0x00, (byte)0x03, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x04, (byte)0x00, +(byte)0x02, (byte)0x00, (byte)0x0d, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02, +(byte)0x00, (byte)0x0e, (byte)0x00, (byte)0x1d, (byte)0x00, (byte)0x01, (byte)0x09, +(byte)0xa0 + }; + + public static void main(String[] args) throws Exception + { + try { + SourceDebugExtension loader = new SourceDebugExtension(); + /* The test program creates a class file from the header + * stored above and adding the content of a SourceDebugExtension + * attribute made of the character 0x02 repeated 68000 times. + * This attribute doesn't follow the syntax specified in JSR 45 + * but it's fine because this test just checks that the JVM is + * able to load a class file with a SourceDebugExtension + * attribute bigger than 64KB. The JVM doesn't try to + * parse the content of the attribute, this work is performed + * by the SA or external tools. + */ + byte[] buf = new byte[header.length + attrSize]; + for(int i=0; i test.out 2>&1 & + +P_PID=$! + +sleep 60 +STATUS=1 + +grep "Test PASSES" test.out > ${NULL} +if [ $? = 0 ]; then + cat test.out + STATUS=0 +fi + +exit $STATUS