Author: lehmi Date: Thu May 16 17:40:18 2024 New Revision: 1917766 URL: http://svn.apache.org/viewvc?rev=1917766&view=rev Log: PDFBOX-5819: added test to ensure the thread safety of Type2CharStringParser as provided by Patrick Corless
Modified: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/CFFParserTest.java Modified: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/CFFParserTest.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/CFFParserTest.java?rev=1917766&r1=1917765&r2=1917766&view=diff ============================================================================== --- pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/CFFParserTest.java (original) +++ pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/CFFParserTest.java Thu May 16 17:40:18 2024 @@ -23,6 +23,8 @@ import static org.junit.jupiter.api.Asse import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.fontbox.util.BoundingBox; import org.apache.pdfbox.io.RandomAccessReadBufferedFile; @@ -117,8 +119,7 @@ class CFFParserTest assertFalse(charStringBytes.isEmpty()); assertEquals(824, testCFFType1Font.getNumCharStrings()); // check some randomly chosen values - assertTrue( - Arrays.equals(new byte[] { -4, 15, 14 }, charStringBytes.get(1)), // + assertTrue(Arrays.equals(new byte[] { -4, 15, 14 }, charStringBytes.get(1)), // "Other char strings byte values than expected"); assertTrue( Arrays.equals(new byte[] { 72, 29, -13, 29, -9, -74, -9, 43, 3, 33, 29, 14 }, @@ -159,10 +160,10 @@ class CFFParserTest } /** - * PDFBOX-4038: Test whether BlueValues and other delta encoded lists are read correctly. The - * test file is from FOP-2432. + * PDFBOX-4038: Test whether BlueValues and other delta encoded lists are read correctly. The test file is from + * FOP-2432. * - * @throws IOException + * @throws IOException */ @Test void testDeltaLists() throws IOException @@ -171,34 +172,95 @@ class CFFParserTest List<Number> blues = (List<Number>) testCFFType1Font.getPrivateDict().get("BlueValues"); // Expected values found for this font - assertNumberList("Blue values are different than expected: " + blues.toString(), - new int[]{-12, 0, 496, 508, 578, 590, 635, 647, 652, 664, 701, 713}, blues); + assertNumberList("Blue values are different than expected: " + blues.toString(), + new int[] { -12, 0, 496, 508, 578, 590, 635, 647, 652, 664, 701, 713 }, blues); @SuppressWarnings("unchecked") - List<Number> otherBlues = (List<Number>) testCFFType1Font.getPrivateDict().get("OtherBlues"); - assertNumberList("Other blues are different than expected: " + otherBlues.toString(), - new int[]{-196, -184}, otherBlues); + List<Number> otherBlues = (List<Number>) testCFFType1Font.getPrivateDict() + .get("OtherBlues"); + assertNumberList("Other blues are different than expected: " + otherBlues.toString(), + new int[] { -196, -184 }, otherBlues); @SuppressWarnings("unchecked") - List<Number> familyBlues = (List<Number>) testCFFType1Font.getPrivateDict().get("FamilyBlues"); - assertNumberList("Other blues are different than expected: " + familyBlues.toString(), - new int[]{-12, 0, 486, 498, 574, 586, 638, 650, 656, 668, 712, 724}, familyBlues); + List<Number> familyBlues = (List<Number>) testCFFType1Font.getPrivateDict() + .get("FamilyBlues"); + assertNumberList("Other blues are different than expected: " + familyBlues.toString(), + new int[] { -12, 0, 486, 498, 574, 586, 638, 650, 656, 668, 712, 724 }, + familyBlues); @SuppressWarnings("unchecked") List<Number> familyOtherBlues = (List<Number>) testCFFType1Font.getPrivateDict() .get("FamilyOtherBlues"); - assertNumberList("Other blues are different than expected: " + familyOtherBlues.toString(), - new int[]{-217, -205}, familyOtherBlues); + assertNumberList("Other blues are different than expected: " + familyOtherBlues.toString(), + new int[] { -217, -205 }, familyOtherBlues); @SuppressWarnings("unchecked") List<Number> stemSnapH = (List<Number>) testCFFType1Font.getPrivateDict().get("StemSnapH"); - assertNumberList("StemSnapH values are different than expected: " + stemSnapH.toString(), - new int[]{115}, stemSnapH); + assertNumberList("StemSnapH values are different than expected: " + stemSnapH.toString(), + new int[] { 115 }, stemSnapH); @SuppressWarnings("unchecked") List<Number> stemSnapV = (List<Number>) testCFFType1Font.getPrivateDict().get("StemSnapV"); - assertNumberList("StemSnapV values are different than expected: " + stemSnapV.toString(), - new int[]{146, 150}, stemSnapV); + assertNumberList("StemSnapV values are different than expected: " + stemSnapV.toString(), + new int[] { 146, 150 }, stemSnapV); + } + + /** + * PDFBOX-5819: ensure thread safety of Type2CharStringParser when parsing the path of a glyph. + * + * @throws InterruptedException + */ + @Test + void testMultiThreadParse() throws InterruptedException + { + CountDownLatch latch = new CountDownLatch(2); + PathRunner pathRunner1 = new PathRunner(latch); + PathRunner pathRunner2 = new PathRunner(latch); + + AtomicBoolean wasCalled = new AtomicBoolean(false); + + Thread.UncaughtExceptionHandler handler = (t, e) -> wasCalled.set(true); + + Thread thread1 = new Thread(pathRunner1); + thread1.setUncaughtExceptionHandler(handler); + Thread thread2 = new Thread(pathRunner2); + thread2.setUncaughtExceptionHandler(handler); + + thread1.start(); + thread2.start(); + + latch.await(); + assertFalse(wasCalled.get()); + } + + private class PathRunner implements Runnable + { + private final CountDownLatch latch; + + public PathRunner(CountDownLatch latch) + { + this.latch = latch; + } + + @Override + public void run() + { + try + { + for (int i = 33; i < 126; i++) + { + testCFFType1Font.getPath(Character.toString(i)); + } + } + catch (Exception e) + { + throw new IllegalStateException(e); + } + finally + { + latch.countDown(); + } + } } private static List<CFFFont> readFont(String filename) throws IOException