Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8351967

JFR: AnnotationIterator should handle num_annotations = 0

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 25
    • 25
    • hotspot
    • None
    • jfr
    • master

      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
           }
         }



            mgronlun Markus Grönlund
            mgronlun Markus Grönlund
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: