This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git


The following commit(s) were added to refs/heads/develop by this push:
     new 4a54ab953 DefinitionBase: Fixed race condition in populating metadata 
on definitions.
4a54ab953 is described below

commit 4a54ab95351c84670c73cbe0261a2316bf638ba5
Author: Josh Tynjala <[email protected]>
AuthorDate: Tue Jul 14 09:52:59 2026 -0700

    DefinitionBase: Fixed race condition in populating metadata on definitions.
    
    Multiple threads may be writing or reading the meta tags on a definition. 
Use a lock to ensure that they play nicely together. Not using synchronized 
because other threads should be able to access non-meta tag parts of the 
definition at the same time without issue.
---
 RELEASE_NOTES.md                                   |   1 +
 .../internal/definitions/DefinitionBase.java       | 150 ++++++++++++++-------
 2 files changed, 102 insertions(+), 49 deletions(-)

diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 5ba236392..06e7da227 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -91,6 +91,7 @@ Apache Royale Compiler 1.0.0
 - compiler: Fixed missing "Generated byte code contains an operand stack 
underflow" error when warnings are reported without other errors.
 - compiler: Fixed null exception when emitting embedded plain text to JS.
 - compiler: Fixed operand stack underflow error when using data binding in 
MXML to assign to `<fx:Object>` property.
+- compiler: Fixed race condition in populating metadata on definitions.
 - debugger: Added missing isolate ID to SWF load and unload events.
 - debugger: Fixed debugger targeting the current JDK version instead of the 
intended minimum JDK version.
 - debugger: Fixed localized messages appearing as unprocessed tokens.
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
index 18f9f72b1..74f0a0f10 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
@@ -26,6 +26,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.royale.abc.ABCConstants;
 import org.apache.royale.abc.semantics.Name;
@@ -144,6 +145,8 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
         
         if (Counter.COUNT_DEFINITIONS)
             countDefinitions();
+
+        metaTagsLock = new ReentrantLock();
     }
 
     // The scope that contains this definition.
@@ -173,6 +176,7 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
     // metaTags is never null. As an optimization, it re-uses a singleton 
empty array when
     // it has nothing in it
     private IMetaTag[] metaTags = singletonEmptyMetaTags;
+    private final ReentrantLock metaTagsLock;
 
     protected static final IMetaTag[] singletonEmptyMetaTags = new IMetaTag[0];
 
@@ -976,29 +980,45 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
 
     protected void addMetaTag(IMetaTag metaTag)
     {
-        IMetaTag[] newMetaTags = new IMetaTag[metaTags.length + 1];
-        System.arraycopy(metaTags, 0, newMetaTags, 0, metaTags.length);
-        newMetaTags[metaTags.length] = metaTag;
-        setMetaTags(newMetaTags);
+        metaTagsLock.lock();
+        try
+        {
+            IMetaTag[] newMetaTags = new IMetaTag[metaTags.length + 1];
+            System.arraycopy(metaTags, 0, newMetaTags, 0, metaTags.length);
+            newMetaTags[metaTags.length] = metaTag;
+            setMetaTags(newMetaTags);
+        }
+        finally
+        {
+            metaTagsLock.unlock();
+        }
     }
 
     public void setMetaTags(IMetaTag[] newMetaTags)
     {
-        if (newMetaTags == null)
+        metaTagsLock.lock();
+        try
         {
-            metaTags = singletonEmptyMetaTags;
-        }
-        else
-        {
-            this.metaTags = newMetaTags;
-            
-            // Use a flag bit to keep track of whether there is a [Deprecated] 
tag.
-            for (IMetaTag metaTag : metaTags)
+            if (newMetaTags == null)
             {
-                String tagName = metaTag.getTagName();
-                if 
(tagName.equals(IMetaAttributeConstants.ATTRIBUTE_DEPRECATED))
-                    setDeprecated();
+                metaTags = singletonEmptyMetaTags;
             }
+            else
+            {
+                this.metaTags = newMetaTags;
+                
+                // Use a flag bit to keep track of whether there is a 
[Deprecated] tag.
+                for (IMetaTag metaTag : metaTags)
+                {
+                    String tagName = metaTag.getTagName();
+                    if 
(tagName.equals(IMetaAttributeConstants.ATTRIBUTE_DEPRECATED))
+                        setDeprecated();
+                }
+            }
+        }
+        finally
+        {
+            metaTagsLock.unlock();
         }
     }
 
@@ -1009,10 +1029,18 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
         // So allocate an empty array here, even if metaTags is null
         List<IMetaTag> list = new ArrayList<IMetaTag>();
 
-        for (IMetaTag tag : metaTags)
+        metaTagsLock.lock();
+        try
+        {
+            for (IMetaTag tag : metaTags)
+            {
+                if (tag.getTagName().equals(name))
+                    list.add(tag);
+            }
+        }
+        finally
         {
-            if (tag.getTagName().equals(name))
-                list.add(tag);
+            metaTagsLock.unlock();
         }
 
         return list.toArray(new IMetaTag[0]);
@@ -1027,10 +1055,18 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
     @Override
     public IMetaTag getMetaTagByName(String name)
     {
-        for (IMetaTag tag : metaTags)
+        metaTagsLock.lock();
+        try
         {
-            if (tag.getTagName().equals(name))
-                return tag;
+            for (IMetaTag tag : metaTags)
+            {
+                if (tag.getTagName().equals(name))
+                    return tag;
+            }
+        }
+        finally
+        {
+            metaTagsLock.unlock();
         }
         return null;
     }
@@ -1699,16 +1735,24 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
     @Override
     public IDeprecationInfo getDeprecationInfo()
     {
-        for (IMetaTag metaTag : metaTags)
+        metaTagsLock.lock();
+        try
         {
-            if 
(metaTag.getTagName().equals(IMetaAttributeConstants.ATTRIBUTE_DEPRECATED))
+            for (IMetaTag metaTag : metaTags)
             {
-                String replacement = 
metaTag.getAttributeValue(IMetaAttributeConstants.NAME_DEPRECATED_REPLACEMENT);
-                String since = 
metaTag.getAttributeValue(IMetaAttributeConstants.NAME_DEPRECATED_SINCE);
-                String message = 
metaTag.getAttributeValue(IMetaAttributeConstants.NAME_DEPRECATED_MESSAGE);
-                return new DeprecationInfo(replacement, since, message);
+                if 
(metaTag.getTagName().equals(IMetaAttributeConstants.ATTRIBUTE_DEPRECATED))
+                {
+                    String replacement = 
metaTag.getAttributeValue(IMetaAttributeConstants.NAME_DEPRECATED_REPLACEMENT);
+                    String since = 
metaTag.getAttributeValue(IMetaAttributeConstants.NAME_DEPRECATED_SINCE);
+                    String message = 
metaTag.getAttributeValue(IMetaAttributeConstants.NAME_DEPRECATED_MESSAGE);
+                    return new DeprecationInfo(replacement, since, message);
+                }
             }
         }
+        finally
+        {
+            metaTagsLock.unlock();
+        }
 
         return null;
     }
@@ -1828,34 +1872,42 @@ public abstract class DefinitionBase implements 
IDocumentableDefinition, IDefini
 
     protected void addFunctionTypeMeta(IFunctionTypeExpressionNode 
funcTypeExprNode, String paramName, ICompilerProject project)
     {
-        int existingIndex = -1;
-        for (int i = 0; i < metaTags.length; i++)
+        metaTagsLock.lock();
+        try
         {
-            IMetaTag otherMetaTag = metaTags[i];
-            if 
(IMetaAttributeConstants.ATTRIBUTE_FUNCTION_TYPE.equals(otherMetaTag.getTagName()))
+            int existingIndex = -1;
+            for (int i = 0; i < metaTags.length; i++)
             {
-                if ((paramName == null && 
otherMetaTag.getAttributeValue(IMetaAttributeConstants.NAME_FUNCTION_TYPE_PARAM_NAME)
 == null)
-                    || (paramName != null && 
paramName.equals(otherMetaTag.getAttributeValue(IMetaAttributeConstants.NAME_FUNCTION_TYPE_PARAM_NAME))))
+                IMetaTag otherMetaTag = metaTags[i];
+                if 
(IMetaAttributeConstants.ATTRIBUTE_FUNCTION_TYPE.equals(otherMetaTag.getTagName()))
                 {
-                    existingIndex = i;
-                    break;
+                    if ((paramName == null && 
otherMetaTag.getAttributeValue(IMetaAttributeConstants.NAME_FUNCTION_TYPE_PARAM_NAME)
 == null)
+                        || (paramName != null && 
paramName.equals(otherMetaTag.getAttributeValue(IMetaAttributeConstants.NAME_FUNCTION_TYPE_PARAM_NAME))))
+                    {
+                        existingIndex = i;
+                        break;
+                    }
                 }
             }
+            ArrayList<IMetaTagAttribute> attributes = new 
ArrayList<IMetaTagAttribute>();
+            if (paramName != null)
+            {
+                attributes.add(new 
MetaTagAttribute(IMetaAttributeConstants.NAME_FUNCTION_TYPE_PARAM_NAME, 
paramName));
+            }
+            attributes.add(new 
MetaTagAttribute(IMetaAttributeConstants.NAME_FUNCTION_TYPE_SIGNATURE, 
funcTypeExprNode.resolveSignature(project)));
+            MetaTag metaTag = new MetaTag(this, 
IMetaAttributeConstants.ATTRIBUTE_FUNCTION_TYPE, attributes.toArray(new 
IMetaTagAttribute[0]));
+            if (existingIndex == -1)
+            {
+                addMetaTag(metaTag);
+            }
+            else
+            {
+                metaTags[existingIndex] = metaTag;
+            }
         }
-        ArrayList<IMetaTagAttribute> attributes = new 
ArrayList<IMetaTagAttribute>();
-        if (paramName != null)
-        {
-            attributes.add(new 
MetaTagAttribute(IMetaAttributeConstants.NAME_FUNCTION_TYPE_PARAM_NAME, 
paramName));
-        }
-        attributes.add(new 
MetaTagAttribute(IMetaAttributeConstants.NAME_FUNCTION_TYPE_SIGNATURE, 
funcTypeExprNode.resolveSignature(project)));
-        MetaTag metaTag = new MetaTag(this, 
IMetaAttributeConstants.ATTRIBUTE_FUNCTION_TYPE, attributes.toArray(new 
IMetaTagAttribute[0]));
-        if (existingIndex == -1)
-        {
-            addMetaTag(metaTag);
-        }
-        else
+        finally
         {
-            metaTags[existingIndex] = metaTag;
+            metaTagsLock.unlock();
         }
     }
 }

Reply via email to