[9] RFR(L) 8158168: SIGSEGV: CollectedHeap::fill_with_objects(HeapWord*, unsigned long, bool)+0xa8

dean.long at oracle.com dean.long at oracle.com
Thu Mar 30 19:27:40 UTC 2017


Actually, the assert inside getChar/putChar shouldn't affect inlining, 
because C1 and C2 will use the intrinsic instead, so I'd like to use 
webrev.2 as is, so I don't have to re-run all the tests.

dl


On 3/30/17 11:24 AM, dean.long at oracle.com wrote:
>
> I would like to go with the webrev.2 version, with asserts removed.  
> All the reviewers have said they are OK with that version, and it 
> allows more complete testing than the minimal version.
>
> dl
>
>
> On 3/23/17 12:03 PM, dean.long at oracle.com wrote:
>>
>> On 3/23/17 11:25 AM, dean.long at oracle.com wrote:
>>
>>> On 3/22/17 1:49 PM, Vladimir Ivanov wrote:
>>>
>>>>> Also, it looks like the changes I made to ASB.appendChars(char[] 
>>>>> s, int
>>>>> off, int end) are not needed.
>>>>
>>>> Agree.
>>>>
>>>>>> Vladimir, don't you need to replace checkIndex with checkOffset in
>>>>>> indexOf and lastIndexOf, so that we allow count == length?
>>>>
>>>> Yes, my bad. Good catch. Updated webrev in place.
>>>>
>>>> FTR I haven't done any extensive testing of the minimized fix.
>>>>
>>>> If we agree to proceed with it, the regression test should be 
>>>> updated as well. I think the viable solution would be to construct 
>>>> broken SBs (using reflection) and invoke affected methods on them.
>>>>
>>>
>>> We can construct broken SBs using the Helper class that gets patched 
>>> into java.lang.  I'll work on that.
>>>
>>
>> Nevermind.  I forgot that some problems can only happen when the SB 
>> is changed half-way through the method.  For example,
>> in append(), we can't force an overflow unless we change the SB after 
>> ensureCapacityInternal() is called.  I could do something like:
>>
>>   760     public AbstractStringBuilder append(int i) {
>> 761 int count = this.count;
>>   762         int spaceNeeded = count + Integer.stringSize(i);
>>   763         ensureCapacityInternal(spaceNeeded);
>>   764         if (isLatin1()) {
>>   >>>>>>          Helper.fuzzValue(this);
>>   765             Integer.getChars(i, spaceNeeded, value);
>>   766         } else {
>>   767             byte[] val = this.value;
>>   >>>>>>          Helper.fuzzValue(this);
>>   768 checkBoundsBeginEnd(count, spaceNeeded, val.length >> 1);
>>   769             Integer.getCharsUTF16(i, spaceNeeded, val);
>>   770         }
>> 771 this.count = spaceNeeded;
>>   772         return this;
>>   773     }
>>
>> where the default Helper.fuzzValue() is an empty method, but the test 
>> would patch in its own version of Helper that changes the ASB field 
>> values.  I like this less than refactoring the checks to StringUTF16.
>>
>> dl
>>
>>> dl
>>>
>>>> Best regards,
>>>> Vladimir Ivanov
>>>>
>>>>>> On 3/22/17 8:35 AM, Vladimir Ivanov wrote:
>>>>>>>>>> So are we convinced that the proposed changes will never lead 
>>>>>>>>>> to a
>>>>>>>>>> crash due to a missing or incorrect bounds check, due to a racy
>>>>>>>>>> use of
>>>>>>>>>> an unsynchronized ASB instance e.g. StringBuilder?
>>>>>>>>>
>>>>>>>>> If only we had a static analysis tool that could tell us if the
>>>>>>>>> code is
>>>>>>>>> safe.  Because we don't, in my initial changeset, we always 
>>>>>>>>> take a
>>>>>>>>> snapshot of the ASB fields by passing those field values to
>>>>>>>>> StringUTF16
>>>>>>>>> before doing checks on them.  And I wrote a test to make sure 
>>>>>>>>> that
>>>>>>>>> those
>>>>>>>>> StringUTF16 interfaces are catching all the underflows and 
>>>>>>>>> overflows I
>>>>>>>>> could imagine, and I added verification code to detect when a 
>>>>>>>>> check
>>>>>>>>> was
>>>>>>>>> missed.
>>>>>>>>>
>>>>>>>>> However, all the reviewers have requested to minimize the 
>>>>>>>>> amount of
>>>>>>>>> changes.  In Vladimir's version, if there is a missing check
>>>>>>>>> somewhere,
>>>>>>>>> then yes it could lead to a crash.
>>>>>>>
>>>>>>> I'd like to point out that asserts and verification code are 
>>>>>>> disabled
>>>>>>> by default. They are invaluable during problem diagnosis, but don't
>>>>>>> help at all from defence-in-depth perspective.
>>>>>>>
>>>>>>> But I agree that it's easier to reason about and test the initial
>>>>>>> version of the fix.
>>>>>>>
>>>>>>>> I wonder if the reviewers have fully realized the potential impact
>>>>>>>> here?
>>>>>>>> This has exposed a flaw in the way intrinsics are used from core
>>>>>>>> classes.
>>>>>>>
>>>>>>> FTR here are the checks I omitted in the minimized version (modulo
>>>>>>> separation of indexOf/lastIndexOf for trusted/non-trusted callers):
>>>>>>>
>>>>>>> http://cr.openjdk.java.net/~vlivanov/dlong/8158168/redundant_checks/ 
>>>>>>>
>>>>>>>
>>>>>>> Other than that, the difference is mainly about undoing 
>>>>>>> refactorings
>>>>>>> and removing verification logic (asserts + checks in the JVM).
>>>>>>>
>>>>>>> There are still unsafe accesses which are considered safe in both
>>>>>>> versions (see StringUTF16.Trusted usages in the initial version 
>>>>>>> [1]).
>>>>>>>
>>>>>>> We used to provide safe wrappers for unsafe intrinsics which 
>>>>>>> makes it
>>>>>>> much easier to reason about code correctness. I'd like to see 
>>>>>>> compact
>>>>>>> string code refactored that way and IMO the initial version by Dean
>>>>>>> is a big step in the right direction.
>>>>>>>
>>>>>>> I still prefer to see a point fix in 9 and major refactoring
>>>>>>> happening in 10, but I'll leave the decision on how to proceed with
>>>>>>> the fix to core-libs folks. After finishing the exercise minimizing
>>>>>>> the fix, I'm much more comfortable with the initial fix [1] (though
>>>>>>> there are changes I consider excessive).
>>>>>>>
>>>>>>> Best regards,
>>>>>>> Vladimir Ivanov
>>>>>>>
>>>>>>> [1] http://cr.openjdk.java.net/~dlong/8158168/webrev.0
>>>>>>>
>>>>>>>>>>>> Some clarifications:
>>>>>>>>>>>>
>>>>>>>>>>>> ============
>>>>>>>>>>>> src/java.base/share/classes/java/lang/String.java:
>>>>>>>>>>>>
>>>>>>>>>>>> The bounds check is needed only in String.nonSyncContentEquals
>>>>>>>>>>>> when it
>>>>>>>>>>>> extracts info from AbstractStringBuilder. I don't see how 
>>>>>>>>>>>> out of
>>>>>>>>>>>> bounds access can happen in String.contentEquals:
>>>>>>>>>>>>          if (n != length()) {
>>>>>>>>>>>>              return false;
>>>>>>>>>>>>          }
>>>>>>>>>>>> ...
>>>>>>>>>>>>              for (int i = 0; i < n; i++) {
>>>>>>>>>>>>                  if (StringUTF16.getChar(val, i) != 
>>>>>>>>>>>> cs.charAt(i)) {
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> OK.
>>>>>>>>>>>
>>>>>>>>>>>> ============
>>>>>>>>>>>> src/java.base/share/classes/java/lang/StringConcatHelper.java:
>>>>>>>>>>>>
>>>>>>>>>>>> I think bounds checks in StringConcatHelper.prepend() are 
>>>>>>>>>>>> skipped
>>>>>>>>>>>> intentionally, since java.lang.invoke.StringConcatFactory
>>>>>>>>>>>> constructs
>>>>>>>>>>>> method handle chains which already contain bounds checks: 
>>>>>>>>>>>> array
>>>>>>>>>>>> length
>>>>>>>>>>>> is precomputed based on argument values and all accesses are
>>>>>>>>>>>> guaranteed to be in bounds.
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> This is calling the trusted version of getChars() with no 
>>>>>>>>>>> bounds
>>>>>>>>>>> checks.  It was a little more obvious when I had the Trusted 
>>>>>>>>>>> inner
>>>>>>>>>>> class.
>>>>>>>>>>>
>>>>>>>>>>>> ============
>>>>>>>>>>>> src/java.base/share/classes/java/lang/StringUTF16.java:
>>>>>>>>>>>>
>>>>>>>>>>>> +    static void putChar(byte[] val, int index, int c) {
>>>>>>>>>>>> +        assert index >= 0 && index < length(val) : 
>>>>>>>>>>>> "Trusted caller
>>>>>>>>>>>> missed bounds check";
>>>>>>>>>>>>
>>>>>>>>>>>> Unfortunately, asserts can affect inlining decisions (since 
>>>>>>>>>>>> they
>>>>>>>>>>>> increase bytecode size). In order to minimize possible 
>>>>>>>>>>>> performance
>>>>>>>>>>>> impact, I suggest to remove them from the fix targeting 9.
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Sure.
>>>>>>>>>>>
>>>>>>>>>>>> ============
>>>>>>>>>>>>      private static int indexOfSupplementary(byte[] value, int
>>>>>>>>>>>> ch, int
>>>>>>>>>>>> fromIndex, int max) {
>>>>>>>>>>>>          if (Character.isValidCodePoint(ch)) {
>>>>>>>>>>>>              final char hi = Character.highSurrogate(ch);
>>>>>>>>>>>>              final char lo = Character.lowSurrogate(ch);
>>>>>>>>>>>> +            checkBoundsBeginEnd(fromIndex, max, value);
>>>>>>>>>>>>
>>>>>>>>>>>> The check is redundant here. fromIndex & max are always 
>>>>>>>>>>>> inbounds by
>>>>>>>>>>>> construction:
>>>>>>>>>>>>
>>>>>>>>>>>>     public static int indexOf(byte[] value, int ch, int
>>>>>>>>>>>> fromIndex) {
>>>>>>>>>>>>         int max = value.length >> 1;
>>>>>>>>>>>>         if (fromIndex < 0) {
>>>>>>>>>>>>             fromIndex = 0;
>>>>>>>>>>>>         } else if (fromIndex >= max) {
>>>>>>>>>>>>             // Note: fromIndex might be near -1>>>1.
>>>>>>>>>>>>             return -1;
>>>>>>>>>>>>         }
>>>>>>>>>>>> ...
>>>>>>>>>>>>             return indexOfSupplementary(value, ch, 
>>>>>>>>>>>> fromIndex, max);
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> OK.
>>>>>>>>>>>
>>>>>>>>>>>> ============
>>>>>>>>>>>> I moved bounds checks from StringUTF16.lastIndexOf/indexOf to
>>>>>>>>>>>> ABS.indexOf/lastIndexOf. I think it's enough to do range 
>>>>>>>>>>>> check on
>>>>>>>>>>>> ABS.value & ABS.count. After that, all accesses should be
>>>>>>>>>>>> inbounds by
>>>>>>>>>>>> construction (in String.indexOf/lastIndexOf):
>>>>>>>>>>>>
>>>>>>>>>>>> jdk/src/java.base/share/classes/java/lang/StringUTF16.java:
>>>>>>>>>>>>     static int lastIndexOf(byte[] src, byte srcCoder, int 
>>>>>>>>>>>> srcCount,
>>>>>>>>>>>>                            String tgtStr, int fromIndex) {
>>>>>>>>>>>>
>>>>>>>>>>>>         int rightIndex = srcCount - tgtCount;
>>>>>>>>>>>>         if (fromIndex > rightIndex) {
>>>>>>>>>>>>             fromIndex = rightIndex;
>>>>>>>>>>>>         }
>>>>>>>>>>>>         if (fromIndex < 0) {
>>>>>>>>>>>>             return -1;
>>>>>>>>>>>>         }
>>>>>>>>>>>>
>>>>>>>>>>>> jdk/src/java.base/share/classes/java/lang/StringUTF16.java:
>>>>>>>>>>>>     public static int lastIndexOf(byte[] src, int srcCount,
>>>>>>>>>>>>                                   byte[] tgt, int tgtCount, 
>>>>>>>>>>>> int
>>>>>>>>>>>> fromIndex) {
>>>>>>>>>>>>         int min = tgtCount - 1;
>>>>>>>>>>>>         int i = min + fromIndex;
>>>>>>>>>>>>         int strLastIndex = tgtCount - 1;
>>>>>>>>>>>>         char strLastChar = getChar(tgt, strLastIndex);
>>>>>>>>>>>>
>>>>>>>>>>>>     startSearchForLastChar:
>>>>>>>>>>>>         while (true) {
>>>>>>>>>>>>             while (i >= min && getChar(src, i) != 
>>>>>>>>>>>> strLastChar) {
>>>>>>>>>>>>
>>>>>>>>>>>> There are 2 places:
>>>>>>>>>>>>   * getChar(tgt, strLastIndex) => getChar(tgt, tgtCount-1) -
>>>>>>>>>>>> inbound
>>>>>>>>>>>>
>>>>>>>>>>>>   * getChar(src, i); i in [ min; min+fromIndex ]
>>>>>>>>>>>>     min = tgtCount - 1
>>>>>>>>>>>>     rightIndex = srcCount - tgtCount
>>>>>>>>>>>>     fromIndex <= rightIndex
>>>>>>>>>>>>
>>>>>>>>>>>>            0 <= min + fromIndex <= min + rightIndex == 
>>>>>>>>>>>> (tgtCount
>>>>>>>>>>>> - 1)
>>>>>>>>>>>> + (srcCount - tgtCount) == srcCount - 1
>>>>>>>>>>>>
>>>>>>>>>>>>     Hence, should be covered by the check on count & value:
>>>>>>>>>>>>       public int lastIndexOf(String str, int fromIndex) {
>>>>>>>>>>>> +         byte[] value = this.value;
>>>>>>>>>>>> +         int count = this.count;
>>>>>>>>>>>> +         byte coder = this.coder;
>>>>>>>>>>>> +         checkIndex(count, value.length >> coder);
>>>>>>>>>>>>           return String.lastIndexOf(value, coder, count, str,
>>>>>>>>>>>> fromIndex);
>>>>>>>>>>>>       }
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> OK, I will go with your version if it's OK with Sherman.
>>>>>>>>>>>
>>>>>>>>>>> dl
>>>>>>>>>>>
>>>>>>>>>>>> Best regards,
>>>>>>>>>>>> Vladimir Ivanov
>>>>>>>>>>>>
>>>>>>>>>>>>> On 3/17/17 5:58 AM, Vladimir Ivanov wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> I have the same concern. Can we fix the immediate 
>>>>>>>>>>>>>>>> problem in
>>>>>>>>>>>>>>>> 9 and
>>>>>>>>>>>>>>>> integrate verification logic in 10?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> OK, Tobias is suggesting having verification logic only
>>>>>>>>>>>>>>> inside the
>>>>>>>>>>>>>>> intrinsics.  Are you suggesting removing that as well?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Yes and put them back in 10.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I'm OK with removing all the verification, but that 
>>>>>>>>>>>>>>> won't reduce
>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>> library changes much.  I could undo the renaming to
>>>>>>>>>>>>>>> Trusted.getChar, but
>>>>>>>>>>>>>>> we would still have the bounds checks moved into 
>>>>>>>>>>>>>>> StringUTF16.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I suggest to go with a point fix for 9: just add missing 
>>>>>>>>>>>>>> range
>>>>>>>>>>>>>> checks.
>>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>
>>>>>
>>>
>>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20170330/ca33ada8/attachment-0001.html>


More information about the hotspot-compiler-dev mailing list