]> source.dussan.org Git - aspectj.git/commitdiff
test for failing synchronization in LocalVariableTable.unpack
authorDmitry Mikhaylov <dmitry@smallgiantgames.com>
Mon, 28 Jun 2021 14:38:28 +0000 (17:38 +0300)
committerDmitry Mikhaylov <dmitry@smallgiantgames.com>
Mon, 28 Jun 2021 14:38:28 +0000 (17:38 +0300)
bcel-builder/src/main/java/org/aspectj/apache/bcel/classfile/LocalVariableTable.java
bcel-builder/src/test/java/org/aspectj/apache/bcel/classfile/tests/LocalVariableTableConcurrencyTest.java [new file with mode: 0644]

index e6415dae6ff43aee070d195f316ff8d967e90514..5452270503767b834cd0d33ff6cf333cc2d43c64 100644 (file)
@@ -63,7 +63,7 @@ import org.aspectj.apache.bcel.Constants;
 
 /**
  * This class represents collection of local variables in a method. This attribute is contained in the <em>Code</em> attribute.
- * 
+ *
  * @version $Id: LocalVariableTable.java,v 1.8 2009/09/15 19:40:12 aclement Exp $
  * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  * @see Code
@@ -99,7 +99,7 @@ public class LocalVariableTable extends Attribute {
 
        /**
         * Construct object from file stream.
-        * 
+        *
         * @param name_index Index in constant pool
         * @param length Content length in bytes
         * @param file Input stream
@@ -117,7 +117,7 @@ public class LocalVariableTable extends Attribute {
        /**
         * Called by objects that are traversing the nodes of the tree implicitely defined by the contents of a Java class. I.e., the
         * hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
-        * 
+        *
         * @param v Visitor object
         */
        @Override
@@ -128,7 +128,7 @@ public class LocalVariableTable extends Attribute {
 
        /**
         * Dump local variable table attribute to file stream in binary format.
-        * 
+        *
         * @param file Output file stream
         * @throws IOException
         */
@@ -189,6 +189,11 @@ public class LocalVariableTable extends Attribute {
                return buf.toString();
        }
 
+       @Override
+       public Object clone() throws CloneNotSupportedException {
+               return super.clone();
+       }
+
        /**
         * @return deep copy of this attribute
         */
@@ -223,7 +228,7 @@ public class LocalVariableTable extends Attribute {
                        dis.close();
                        data = null; // throw it away now
                } catch (IOException e) {
-                       throw new RuntimeException("Unpacking of LocalVariableTable attribute failed");
+                       throw new RuntimeException("Unpacking of LocalVariableTable attribute failed", e);
                }
                isInPackedState = false;
        }
diff --git a/bcel-builder/src/test/java/org/aspectj/apache/bcel/classfile/tests/LocalVariableTableConcurrencyTest.java b/bcel-builder/src/test/java/org/aspectj/apache/bcel/classfile/tests/LocalVariableTableConcurrencyTest.java
new file mode 100644 (file)
index 0000000..da9b8c2
--- /dev/null
@@ -0,0 +1,94 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Andy Clement -     initial implementation
+ * ******************************************************************/
+
+package org.aspectj.apache.bcel.classfile.tests;
+
+import org.aspectj.apache.bcel.classfile.Code;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.classfile.LocalVariableTable;
+import org.aspectj.apache.bcel.classfile.Method;
+import org.aspectj.apache.bcel.classfile.tests.BcelTestCase;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicReference;
+
+
+public class LocalVariableTableConcurrencyTest extends BcelTestCase {
+
+       private final int nThreads = Runtime.getRuntime().availableProcessors();
+
+       private final ExecutorService[] workers = new ExecutorService[nThreads];
+
+       private LocalVariableTable reference;
+
+       protected void setUp() throws Exception {
+               super.setUp();
+               for (int i = 0; i < nThreads; i++) workers[i] = Executors.newSingleThreadExecutor();
+
+               JavaClass clazz = getClassFromJar("SimpleGenericsProgram");
+
+               Method mainMethod = getMethod(clazz,"main");
+               Code codeAttr = (Code) findAttribute("Code",mainMethod.getAttributes());
+
+               reference =
+                               (LocalVariableTable) findAttribute("LocalVariableTable",codeAttr.getAttributes());
+       }
+
+       private LocalVariableTable createReferenceCopy() {
+               try {
+                       return (LocalVariableTable) reference.clone();
+               } catch (CloneNotSupportedException e) {
+                       throw new RuntimeException("Faileed to clone LocalVariableTable", e);
+               }
+       }
+
+       public void testLocalVariableTableAttributeConcurrency() throws RuntimeException, InterruptedException {
+               final AtomicReference<RuntimeException> error = new AtomicReference<>();
+               for (int i = 0; i < 100000; i++) {
+                       LocalVariableTable sharedInstance = createReferenceCopy();
+                       CountDownLatch preStart = new CountDownLatch(nThreads);
+                       Semaphore start = new Semaphore(0);
+                       CountDownLatch finish = new CountDownLatch(nThreads);
+
+                       for (int j = 0; j < nThreads; j++) {
+                               final boolean needsDelay = j > 0;
+                               workers[j].execute(() -> {
+                                       preStart.countDown();
+                                       start.acquireUninterruptibly();
+                                       // trying to trigger concurrent unpacking - one tread should enter unpack() when other is about to leave it
+                                       if (needsDelay) createReferenceCopy().getTableLength();
+                                       try {
+                                               sharedInstance.getTableLength();
+                                       }
+                                       catch (RuntimeException ex) {
+                                               error.compareAndSet(null, ex);
+                                       }
+                                       finish.countDown();
+                               });
+                       }
+
+                       preStart.await();
+                       start.release(nThreads);
+                       finish.await();
+
+                       if (error.get() != null) throw error.get();
+               }
+       }
+
+       protected void tearDown() throws Exception {
+               for (int i = 0; i < nThreads; i++) if (workers[i] != null) workers[i].shutdownNow();
+               super.tearDown();
+       }
+}