Path: blob/master/test/jdk/sun/security/util/ManifestDigester/FindSection.java
41152 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.lang.reflect.Constructor;24import java.lang.reflect.Field;25import java.lang.reflect.Method;26import java.util.Arrays;27import java.util.concurrent.Callable;28import java.util.function.Consumer;2930import sun.security.util.ManifestDigester;3132import org.testng.annotations.Test;33import org.testng.annotations.BeforeClass;34import org.testng.annotations.BeforeMethod;35import org.testng.annotations.DataProvider;36import org.testng.annotations.Factory;3738import static java.nio.charset.StandardCharsets.UTF_8;39import static org.testng.Assert.*;4041/**42* @test43* @bug 821737544* @modules java.base/sun.security.util:+open45* @compile ../../tools/jarsigner/Utils.java46* @run testng/othervm FindSection47* @summary Check {@link ManifestDigester#findSection}.48*/49public class FindSection {5051/*52* TODO:53* FIXED_8217375 is not intended to keep. it is intended to show what54* exactly has changed with respect to the previous version for which no55* such test existed.56*/57static final boolean FIXED_8217375 = true;5859/**60* {@link ManifestDigester.Entry#digestWorkaround} should not feed the61* trailing blank line into the digester. Before resolution of 8217375 it62* fed the trailing blank line into the digest if the second line break63* was at the end of the file due to <pre>64* if (allBlank || (i == len-1)) {65* if (i == len-1)66* pos.endOfSection = i;67* else68* pos.endOfSection = last;69* </pre> in {@link ManifestDigester#findSection}. In that case at the end70* of the manifest file, {@link ManifestDigester.Entry#digestWorkaround}71* would have produced the same digest as72* {@link ManifestDigester.Entry#digest} which was wrong and without effect73* at best.74* <p>75* Once this fix is accepted, this flag can be removed along with76* {@link #actualEndOfSection8217375}.77*/78static final boolean FIXED_8217375_EOF_ENDOFSECTION = FIXED_8217375;7980/**81* {@link ManifestDigester.Position.endOfSection} usually points to the82* start position of the blank line trailing a section minus one.83* If a {@link ManifestDigester.Position} returned by84* {@link ManifestDigester#findSection} is based on a portion that starts85* with a blank line, above statement is (or was) not true, because of the86* initialization of {@code last} in {@link ManifestDigester#findSection}87* <pre>88* int last = offset;89* </pre>90* which would point after incrementing it in {@code pos.endOfSection + 1}91* on line 128 (line number before this change) or {@code int sectionLen =92* pos.endOfSection-start+1;} on line 133 (line number before this change)93* at one byte after the first line break character of usually two and94* possibly (assuming "{@code \r\n}" default line break normally) in between95* the two characters of a line break. After subtracting again the index of96* the section start position on former line 133, the last byte would be97* missed to be digested by {@link ManifestDigester.Entry#digestWorkaround}.98* <p>99* All this, however could possibly matter (or have mattered) only when100* {@link ManifestDigester#findSection} was invoked with an offset position101* pointing straight to a line break which happens if a manifest starts102* with an empty line or if there are superfluous blank lines between103* sections in both cases no useful manifest portion is identified.104* Superfluous blank lines are not identified as sections (because they105* don't have a name and specifically don't meet {@code if (len > 6) {} on106* former line 136. Manifests starting with a line break are not any more107* useful either.108* <p>109* Once this fix is accepted, this flag can be removed along with110* {@link #actualEndOfSection8217375}.111*/112static final boolean FIXED_8217375_STARTWITHBLANKLINE_ENDOFSECTION =113FIXED_8217375;114115static Constructor<?> PositionConstructor;116static Method findSection;117static Field rawBytes;118static Field endOfFirstLine;119static Field endOfSection;120static Field startOfNext;121122@BeforeClass123public static void setFindSectionAccessible() throws Exception {124Class<?> Position = Arrays.stream(ManifestDigester.class.125getDeclaredClasses()).filter(c -> c.getSimpleName().126equals("Position")).findFirst().get();127PositionConstructor = Position.getDeclaredConstructor();128PositionConstructor.setAccessible(true);129findSection = ManifestDigester.class.getDeclaredMethod("findSection",130int.class, Position);131findSection.setAccessible(true);132rawBytes = ManifestDigester.class.getDeclaredField("rawBytes");133rawBytes.setAccessible(true);134endOfFirstLine = Position.getDeclaredField("endOfFirstLine");135endOfFirstLine.setAccessible(true);136endOfSection = Position.getDeclaredField("endOfSection");137endOfSection.setAccessible(true);138startOfNext = Position.getDeclaredField("startOfNext");139startOfNext.setAccessible(true);140}141142static class Position {143final int endOfFirstLine; // not including newline character144145final int endOfSection; // end of section, not including the blank line146// between sections147final int startOfNext; // the start of the next section148149Position(Object pos) throws ReflectiveOperationException {150endOfFirstLine = FindSection.endOfFirstLine.getInt(pos);151endOfSection = FindSection.endOfSection.getInt(pos);152startOfNext = FindSection.startOfNext.getInt(pos);153}154}155156Position findSection(byte[] manifestBytes)157throws ReflectiveOperationException {158ManifestDigester manDig = new ManifestDigester("\n\n".getBytes(UTF_8));159FindSection.rawBytes.set(manDig, manifestBytes);160Object pos = PositionConstructor.newInstance();161Object result = findSection.invoke(manDig, offset, pos);162if (Boolean.FALSE.equals(result)) {163return null; // indicates findSection having returned false164} else {165return new Position(pos);166}167}168169@DataProvider(name = "parameters")170public static Object[][] parameters() {171return new Object[][] { { 0 }, { 42 } };172}173174@Factory(dataProvider = "parameters")175public static Object[] createTests(int offset) {176return new Object[]{ new FindSection(offset) };177}178179final int offset;180181FindSection(int offset) {182this.offset = offset;183}184185@BeforeMethod186public void verbose() {187System.out.println("offset = " + offset);188}189190Position findSection(String manifestString)191throws ReflectiveOperationException {192byte[] manifestBytes = manifestString.getBytes(UTF_8);193byte[] manifestWithOffset = new byte[manifestBytes.length + offset];194System.arraycopy(manifestBytes, 0, manifestWithOffset, offset,195manifestBytes.length);196return findSection(manifestWithOffset);197}198199/**200* Surprising, but the offset actually makes a difference in201* {@link ManifestDigester#findSection} return value.202*/203@SuppressWarnings("unused")204int actualEndOfFirstLine8217375(int correctPosition) {205// if the parsed portion of the manifest starts with a blank line,206// and offset is 0, "pos.endOfFirstLine = -1;" probably denoting a207// yet uninitialized value coincides with the assignment by208// "pos.endOfFirstLine = i-1;" if i == 0 and209// "if (pos.endOfFirstLine == -1)" after "case '\n':" happens to210// become true even though already assigned.211if (offset == 0 && correctPosition == -1 && !FIXED_8217375) return 0;212return correctPosition;213}214215@SuppressWarnings("unused")216int actualEndOfSection8217375(int correctPosition, boolean eof, int lbl) {217// if the parsed portion of the manifest ends with a blank line and218// just before eof, the blank line is included in Position.endOfSection/219// Section.length (the one usually without blank line as well as in220// Position.startOfNext/Section.lengthWithBlankLine) which is used221// in digestWorkaround (independent of the digest without workaround)222if (eof && !FIXED_8217375_EOF_ENDOFSECTION) {223return correctPosition + lbl;224} else if (correctPosition == -1225&& !FIXED_8217375_STARTWITHBLANKLINE_ENDOFSECTION) {226return 0;227} else {228return correctPosition;229}230}231232AssertionError collectErrors(AssertionError a, Runnable run) {233try {234run.run();235} catch (AssertionError e) {236if (a == null) a = new AssertionError();237a.addSuppressed(e);238}239return a;240}241242void assertPosition(Position pos,243int endOfFirstLine, int endOfSection, int startOfNext) {244AssertionError a = null;245a = collectErrors(a, () -> assertEquals(246pos.endOfFirstLine, endOfFirstLine + offset, "endOfFirstLine"));247a = collectErrors(a, () -> assertEquals(248pos.endOfSection, endOfSection + offset, "endOfSection"));249a = collectErrors(a, () -> assertEquals(250pos.startOfNext, startOfNext + offset, "startOfNext"));251if (a != null) throw a;252}253254void catchCrCausesIndexOutOfBoundsException(255Callable<Position> test, Consumer<Position> asserts) {256try {257Position x = test.call();258if (!FIXED_8217375) fail();259asserts.accept(x);260} catch (Exception e) {261if (e instanceof IndexOutOfBoundsException ||262e.getCause() instanceof IndexOutOfBoundsException) {263if (FIXED_8217375) throw new AssertionError(e);264} else {265throw new AssertionError(e);266}267}268}269270@Test271public void testEmpty() throws Exception {272assertNull(findSection(""));273}274275@Test276public void testOneLineBreakCr() throws Exception {277catchCrCausesIndexOutOfBoundsException(278() -> findSection("\r"),279p -> assertPosition(p,280-1, actualEndOfSection8217375(-1, false, 1), 1)281);282}283284@Test285public void testOneLineBreakLf() throws Exception {286assertPosition(findSection("\n"),287-1, actualEndOfSection8217375(-1, false, 1), 1);288}289290@Test291public void testOneLineBreakCrLf() throws Exception {292assertPosition(findSection("\r\n"),293actualEndOfFirstLine8217375(-1),294actualEndOfSection8217375(-1, true, 2),2952);296}297298@Test299public void testSpaceAndLineBreakCr() throws Exception {300catchCrCausesIndexOutOfBoundsException(301() -> findSection(" \r"),302p -> assertPosition(p, 2, 3, 4)303);304}305306@Test307public void testSpaceAndOneLineBreakLf() throws Exception {308assertPosition(findSection(" \n"), 2, 3, 4);309}310311@Test312public void testSpaceAndOneLineBreakCrLf() throws Exception {313assertPosition(findSection(" \r\n"), 2, 4, 5);314}315316@Test317public void testOneLineBreakCrAndSpace() throws Exception {318assertPosition(findSection("\r "),319-1, actualEndOfSection8217375(-1, false, 1), 1);320}321322@Test323public void testOneLineBreakLfAndSpace() throws Exception {324assertPosition(findSection("\n "),325-1, actualEndOfSection8217375(-1, false, 1), 1);326}327328@Test329public void testOneLineBreakCrLfAndSpace() throws Exception {330assertPosition(findSection("\r\n "),331actualEndOfFirstLine8217375(-1),332actualEndOfSection8217375(-1, false, 1),3332);334}335336@Test337public void testCrEof() throws Exception {338catchCrCausesIndexOutOfBoundsException(339() -> findSection("abc\r"),340p -> assertPosition(p, 2, 3, 4)341);342}343344@Test345public void testLfEof() throws Exception {346assertPosition(findSection("abc\n"), 2, 3, 4);347}348349@Test350public void testCrLfEof() throws Exception {351assertPosition(findSection("abc\r\n"), 2, 4, 5);352}353354@Test355public void testCrContinued() throws Exception {356assertPosition(findSection("abc\rxyz\r\n\r\n "), 2, 8, 11);357}358359@Test360public void testLfContinued() throws Exception {361assertPosition(findSection("abc\nxyz\r\n\r\n "), 2, 8, 11);362}363364@Test365public void testCrLfContinued() throws Exception {366assertPosition(findSection("abc\r\nxyz\r\n\r\n "), 2, 9, 12);367}368369@Test370public void testCrCrEof() throws Exception {371catchCrCausesIndexOutOfBoundsException(372() -> findSection("abc\r\nxyz\r\r"),373p -> assertPosition(p,3742, actualEndOfSection8217375(8, true, 1), 10)375);376}377378@Test379public void testCrCrContinued() throws Exception {380assertPosition(findSection("abc\r\nxyz\r\r "), 2, 8, 10);381}382383@Test384public void testLfLfEof() throws Exception {385assertPosition(findSection("abc\r\nxyz\n\n"),3862, actualEndOfSection8217375(8, true, 1), 10);387}388389@Test390public void testLfLfContinued() throws Exception {391assertPosition(findSection("abc\r\nxyz\n\n "), 2, 8, 10);392}393394@Test395public void testCrLfEof2() throws Exception {396assertPosition(findSection("abc\r\nxyz\r\n"), 2, 9, 10);397}398399@Test400public void testMainSectionNotTerminatedWithLineBreak() throws Exception {401assertNull(findSection("abc\r\nxyz\r\n "));402}403404@Test405public void testLfCrEof() throws Exception {406catchCrCausesIndexOutOfBoundsException(407() -> findSection("abc\r\nxyz\n\r"),408p -> assertPosition(p,4092, actualEndOfSection8217375(8, true, 1), 10)410);411}412413@Test414public void testLfCrContinued() throws Exception {415assertPosition(findSection("abc\r\nxyz\n\r "), 2, 8, 10);416}417418@Test419public void testCrLfCrEof() throws Exception {420catchCrCausesIndexOutOfBoundsException(421() -> findSection("abc\r\nxyz\r\n\r"),422p -> assertPosition(p,4232, actualEndOfSection8217375(9, true, 2), 11)424);425}426427@Test428public void testCrLfCrContinued() throws Exception {429assertPosition(findSection("abc\r\nxyz\r\n\r "), 2, 9, 11);430}431432@Test433public void testCrLfLfEof() throws Exception {434assertPosition(findSection("abc\r\nxyz\r\n\n"),4352, actualEndOfSection8217375(9, true, 1), 11);436}437438@Test439public void testCrLfLfContinued() throws Exception {440assertPosition(findSection("abc\r\nxyz\r\n\n "), 2, 9, 11);441}442443@Test444public void testCrLfCrLfEof() throws Exception {445assertPosition(findSection("abc\r\nxyz\r\n\r\n"),4462, actualEndOfSection8217375(9, true, 2), 12);447}448449@Test450public void testCrLfCfLfContinued() throws Exception {451assertPosition(findSection("abc\r\nxyz\r\n\r\n "), 2, 9, 12);452}453454@Test455public void testCrLfCrCrEof() throws Exception {456assertPosition(findSection("abc\r\nxyz\r\n\r\r"), 2, 9, 11);457}458459@Test460public void testCrLfCrCrContinued() throws Exception {461assertPosition(findSection("abc\r\nxyz\r\n\r\r "), 2, 9, 11);462}463464@Test465public void testCrLfLfCrEof() throws Exception {466assertPosition(findSection("abc\r\nxyz\r\n\n\r"), 2, 9, 11);467}468469@Test470public void testCrLfLfCrContinued() throws Exception {471assertPosition(findSection("abc\r\nxyz\r\n\n\r "), 2, 9, 11);472}473474@Test475public void testCrLfCrLfCrEof() throws Exception {476assertPosition(findSection("abc\r\nxyz\r\n\r\n\r"), 2, 9, 12);477}478479@Test480public void testCrLfCfLfCrContinued() throws Exception {481assertPosition(findSection("abc\r\nxyz\r\n\r\n\r "), 2, 9, 12);482}483484@Test485public void testCrLfCrLfContinued() throws Exception {486assertPosition(findSection("abc\r\nxyz\r\n\r\n "), 2, 9, 12);487}488489@Test490public void testCrLfLfLfEof() throws Exception {491assertPosition(findSection("abc\r\nxyz\r\n\n\n"), 2, 9, 11);492}493494@Test495public void testCrLfLfLfContinued() throws Exception {496assertPosition(findSection("abc\r\nxyz\r\n\n\n "), 2, 9, 11);497}498499@Test500public void testCrLfCrLfLfContinued() throws Exception {501assertPosition(findSection("abc\r\nxyz\r\n\r\n\n "), 2, 9, 12);502}503504@Test505public void testCrLfCrCrLfEof() throws Exception {506assertPosition(findSection("abc\r\nxyz\r\n\r\r\n"), 2, 9, 11);507}508509@Test510public void testCrLfCrCrLfContinued() throws Exception {511assertPosition(findSection("abc\r\nxyz\r\n\r\r\n "), 2, 9, 11);512}513514@Test515public void testCrLfLfCrLfEof() throws Exception {516assertPosition(findSection("abc\r\nxyz\r\n\n\r\n"), 2, 9, 11);517}518519@Test520public void testCrLfLfCrLfContinued() throws Exception {521assertPosition(findSection("abc\r\nxyz\r\n\n\r\n "), 2, 9, 11);522}523524@Test525public void testCrLfCrLfCrLfEof() throws Exception {526assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\n"), 2, 9, 12);527}528529@Test530public void testCrLfCfLfCrLfContinued() throws Exception {531assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\n "), 2, 9, 12);532}533534@Test535public void testCrLfLfCrCrEof() throws Exception {536assertPosition(findSection("abc\r\nxyz\r\n\n\r\r"), 2, 9, 11);537}538539@Test540public void testCrLfCrLfCrCrEof() throws Exception {541assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\r"), 2, 9, 12);542}543544@Test545public void testCrLfCrLfCrContinued() throws Exception {546assertPosition(findSection("abc\r\nxyz\r\n\r\n\r "), 2, 9, 12);547}548549@Test550public void testCrLfLfLfCrEof() throws Exception {551assertPosition(findSection("abc\r\nxyz\r\n\n\n\r"), 2, 9, 11);552}553554@Test555public void testCrLfLfCrLfCrEof() throws Exception {556assertPosition(findSection("abc\r\nxyz\r\n\n\r\n\r"), 2, 9, 11);557}558559@Test560public void testCrLfLfLfLfEof() throws Exception {561assertPosition(findSection("abc\r\nxyz\r\n\n\n\n"), 2, 9, 11);562}563564@Test565public void testCrLfLfCrLfLfEof() throws Exception {566assertPosition(findSection("abc\r\nxyz\r\n\n\r\n\n"), 2, 9, 11);567}568569@Test570public void testCrLfLfCrCrLfEof() throws Exception {571assertPosition(findSection("abc\r\nxyz\r\n\n\r\r\n"), 2, 9, 11);572}573574@Test575public void testCrLfCrLfCrCrLfEof() throws Exception {576assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\r\n"), 2, 9, 12);577}578579@Test580public void testCrLfCrLfCrLfContinued() throws Exception {581assertPosition(findSection("abc\r\nxyz\r\n\r\n\r\n "), 2, 9, 12);582}583584@Test585public void testCrLfLfLfCrLfEof() throws Exception {586assertPosition(findSection("abc\r\nxyz\r\n\n\n\r\n"), 2, 9, 11);587}588589@Test590public void testCrLfLfCrLfCrLfEof() throws Exception {591assertPosition(findSection("abc\r\nxyz\r\n\n\r\n\r\n"), 2, 9, 11);592}593594@Test595public void testCrLfCrCrLfCrCrEof() throws Exception {596assertPosition(findSection("abc\r\nxyz\r\n\r\r\n\r"), 2, 9, 11);597}598599@Test600public void testCrLfCrCrCrCrEof() throws Exception {601assertPosition(findSection("abc\r\nxyz\r\n\r\r\r"), 2, 9, 11);602}603604@Test605public void testCrLfCrCrLfLfEof() throws Exception {606assertPosition(findSection("abc\r\nxyz\r\n\r\r\n\n"), 2, 9, 11);607}608609@Test610public void testCrLfCrCrLfCrLfEof() throws Exception {611assertPosition(findSection("abc\r\nxyz\r\n\r\r\n\r\n"), 2, 9, 11);612}613614@Test615public void testCrLfCrCrCrLfEof() throws Exception {616assertPosition(findSection("abc\r\nxyz\r\n\r\r\r\n"), 2, 9, 11);617}618619/*620* endOfFirstLine is the same regardless of the line break delimiter621*/622@Test623public void testEndOfFirstLineVsLineBreak() throws Exception {624for (String lb : new String[] { "\r", "\n", "\r\n" }) {625Position p = findSection("abc" + lb + "xyz" + lb + lb + " ");626627// main assertion showing endOfFirstLine independent of line break628assertEquals(p.endOfFirstLine, 2 + offset);629630// assert remaining positions as well just for completeness631assertPosition(p, 2, 5 + 2 * lb.length(), 6 + 3 * lb.length());632}633}634635/*636* '\r' at the end of the bytes causes index out of bounds exception637*/638@Test639public void testCrLastCausesIndexOutOfBounds() throws Exception {640catchCrCausesIndexOutOfBoundsException(641() -> findSection("\r"),642p -> assertPosition(p,643-1, actualEndOfSection8217375(-1, true, 1), 1)644);645}646647/*648* endOfSection includes second line break if at end of bytes only649*/650@Test651public void testEndOfSectionWithLineBreakVsEof() throws Exception {652AssertionError errors = new AssertionError("offset = " + offset);653for (String lb : new String[] { "\r", "\n", "\r\n" }) {654for (boolean eof : new boolean[] { false, true }) {655Position p;656try {657p = findSection("abc" + lb + lb + (eof ? "" : "xyz"));658} catch (RuntimeException | ReflectiveOperationException e) {659if ((e instanceof IndexOutOfBoundsException ||660e.getCause() instanceof IndexOutOfBoundsException)661&& eof && "\r".equals(lb) && !FIXED_8217375) continue;662throw e;663}664665AssertionError a = new AssertionError("offset = " + offset666+ ", lb = " + Utils.escapeStringWithNumbers(lb) + ", "667+ "eof = " + eof);668669// main assertion showing endOfSection including second line670// break when at end of file671a = collectErrors(a, () -> assertEquals(672p.endOfSection,673actualEndOfSection8217375(6742 + lb.length() + offset, eof, lb.length()) ));675676// assert remaining positions as well just for completeness677a = collectErrors(a, () -> assertPosition(p,6782,679actualEndOfSection8217375(6802 + lb.length(), eof, lb.length()),6813 + lb.length() * 2));682683if (a.getSuppressed().length > 0) errors.addSuppressed(a);684}685}686if (errors.getSuppressed().length > 0) throw errors;687}688689/*690* returns position even if only one line break before end of bytes.691* because no name will be found the result will be skipped and no entry692* will be created.693*/694@Test695public void testReturnPosVsEof() throws Exception {696for (String lb : new String[] { "\r", "\n", "\r\n" }) {697for (boolean eof : new boolean[] { false, true }) {698try {699Position p = findSection("abc" + lb + (eof ? "" : "xyz"));700assertTrue(p != null == eof);701} catch (RuntimeException | ReflectiveOperationException e) {702if ((e instanceof IndexOutOfBoundsException ||703e.getCause() instanceof IndexOutOfBoundsException)704&& eof && "\r".equals(lb) && !FIXED_8217375) continue;705throw e;706}707}708}709}710711/*712* it could be normally be expected that startOfNext would point to the713* start of the next section after a blank line but that is not the case714* if a section ends with only one line break and no blank line immediately715* before eof of the manifest.716* such an entry will be digested without the trailing blank line which is717* only fine until another section should be added afterwards.718*/719@Test720public void testStartOfNextPointsToEofWithNoBlankLine() throws Exception {721for (String lb : new String[] { "\r", "\n", "\r\n" }) {722for (boolean blank : new boolean[] { false, true }) {723String manifest = "abc" + lb + "xyz" + lb + (blank ? lb : "");724try {725Position p = findSection(manifest);726727// assert that startOfNext points to eof in all cases728// whether with or without a blank line before eof729assertEquals(p.startOfNext, manifest.length() + offset);730731// assert remaining positions as well just for completeness732assertPosition(p,7332,734actualEndOfSection8217375(7355 + lb.length() * 2,736true,737blank ? lb.length() : 0),738manifest.length());739} catch (RuntimeException | ReflectiveOperationException e) {740if ((e instanceof IndexOutOfBoundsException ||741e.getCause() instanceof IndexOutOfBoundsException)742&& "\r".equals(lb) && !FIXED_8217375) continue;743throw e;744}745}746}747}748749}750751752