class AnnotationIterator : public StackObj {
private:
const InstanceKlass* _ik;
// ensure _limit field is declared before _buffer
int _limit; // length of annotations array
const address _buffer;
mutable int _current; // annotation
mutable int _next; // annotation
public:
AnnotationIterator(const InstanceKlass* ik, AnnotationArray* ar) : _ik(ik),
_limit(ar != nullptr ? ar->length() : 0),
_buffer(_limit > 2 ? ar->adr_at(2) : nullptr),
_current(0),
_next(0) {
if (_buffer != nullptr) {
_limit -= 2; // subtract sizeof(u2) number of annotations field
}
}
JVMS section 4.7.16. The RuntimeVisibleAnnotations Attribute:
https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-4.html#jvms-4.7.16
The RuntimeVisibleAnnotations attribute has the following format:
RuntimeVisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
In ClassFileParser, the AnnotationArray is constructed by including the "num_annotations" (u2) item. That is why there are offsets by 2 in the AnnotationIterator.
But the above AnnotationIterator contains a bug that a corner case can trigger: It is perfectly legal, although probably an oversight in practice, or even a bug, for bytecode generators/transformers, to construct a RuntimeVisibleAnnotations attribute with an item "num_annotations" == 0.
In that case, no limit adjustment will be done because the adjustment to _limit is conditional on _buffer != nullptr. Instead, the code will SIGSEGV when attempting to dereference the non-existing _buffer field (because _next (0) < _limit (2), i.e. has_next() == true).
The adjustment to _limit should instead be made like this:
diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
index 8c3b895345f..5e4e4a5cf5f 100644
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
@@ -338,7 +338,7 @@ class AnnotationIterator : public StackObj {
_buffer(_limit > 2 ? ar->adr_at(2) : nullptr),
_current(0),
_next(0) {
- if (_buffer != nullptr) {
+ if (_limit >= 2) {
_limit -= 2; // subtract sizeof(u2) number of annotations field
}
}
private:
const InstanceKlass* _ik;
// ensure _limit field is declared before _buffer
int _limit; // length of annotations array
const address _buffer;
mutable int _current; // annotation
mutable int _next; // annotation
public:
AnnotationIterator(const InstanceKlass* ik, AnnotationArray* ar) : _ik(ik),
_limit(ar != nullptr ? ar->length() : 0),
_buffer(_limit > 2 ? ar->adr_at(2) : nullptr),
_current(0),
_next(0) {
if (_buffer != nullptr) {
_limit -= 2; // subtract sizeof(u2) number of annotations field
}
}
JVMS section 4.7.16. The RuntimeVisibleAnnotations Attribute:
https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-4.html#jvms-4.7.16
The RuntimeVisibleAnnotations attribute has the following format:
RuntimeVisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
In ClassFileParser, the AnnotationArray is constructed by including the "num_annotations" (u2) item. That is why there are offsets by 2 in the AnnotationIterator.
But the above AnnotationIterator contains a bug that a corner case can trigger: It is perfectly legal, although probably an oversight in practice, or even a bug, for bytecode generators/transformers, to construct a RuntimeVisibleAnnotations attribute with an item "num_annotations" == 0.
In that case, no limit adjustment will be done because the adjustment to _limit is conditional on _buffer != nullptr. Instead, the code will SIGSEGV when attempting to dereference the non-existing _buffer field (because _next (0) < _limit (2), i.e. has_next() == true).
The adjustment to _limit should instead be made like this:
diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
index 8c3b895345f..5e4e4a5cf5f 100644
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
@@ -338,7 +338,7 @@ class AnnotationIterator : public StackObj {
_buffer(_limit > 2 ? ar->adr_at(2) : nullptr),
_current(0),
_next(0) {
- if (_buffer != nullptr) {
+ if (_limit >= 2) {
_limit -= 2; // subtract sizeof(u2) number of annotations field
}
}
- links to
-
Commit(master) openjdk/jdk/2eecf159
-
Review(master) openjdk/jdk/24037