Defect #34108

"Is duplicate of" and "Has duplicate" issue relations can be a circular reference

Added by Go MAEDA 13 days ago. Updated 11 days ago.

Status:NewStart date:
Priority:NormalDue date:
Assignee:-% Done:

0%

Category:Issues
Target version:Candidate for next minor release
Resolution: Affected version:

Description

You can make two issues circular reference with the following steps:

1. Suppose that there are two issues A and B
2. Open the issue A and add a "Is duplicate of" relation to issue B
3. Open the issue B and add a "Is duplicate of" relation to issue A

After the above operation, each of those two issues will have two relations against the opponent, "Has duplicate and Is duplicate of" (see the screenshot below). Such logically wrong relations should not be created.

The curcular reference causes a serious problem when you try to close one of those issues. If you attempt to close the issue, Redmine raises SystemStackError exception and hangs.

SystemStackError (stack level too deep):

lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb:92:in `detect'
lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb:92:in `block in custom_field_values'
lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb:81:in `collect'
lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb:81:in `custom_field_values'
app/models/journal.rb:193:in `start'
app/models/journal.rb:77:in `initialize'
app/models/issue.rb:823:in `init_journal'
app/models/issue.rb:1859:in `block in close_duplicates'
app/models/issue.rb:1851:in `each'
app/models/issue.rb:1851:in `close_duplicates'
app/models/issue.rb:215:in `create_or_update'
app/models/issue.rb:1862:in `block in close_duplicates'
app/models/issue.rb:1851:in `each'
app/models/issue.rb:1851:in `close_duplicates'
app/models/issue.rb:215:in `create_or_update'
app/models/issue.rb:1862:in `block in close_duplicates'
app/models/issue.rb:1851:in `each'
app/models/issue.rb:1851:in `close_duplicates'
app/models/issue.rb:215:in `create_or_update'
app/models/issue.rb:1862:in `block in close_duplicates'
app/models/issue.rb:1851:in `each'
app/models/issue.rb:1851:in `close_duplicates'
app/models/issue.rb:215:in `create_or_update'
app/models/issue.rb:1862:in `block in close_duplicates'
app/models/issue.rb:1851:in `each'
app/models/issue.rb:1851:in `close_duplicates'
app/models/issue.rb:215:in `create_or_update'
app/models/issue.rb:1862:in `block in close_duplicates'
app/models/issue.rb:1851:in `each'
app/models/issue.rb:1851:in `close_duplicates'
app/models/issue.rb:215:in `create_or_update'
app/models/issue.rb:1862:in `block in close_duplicates'
app/models/issue.rb:1851:in `each'

circular-relation.png (17 KB) Go MAEDA, 2020-10-13 05:40

fixed-34108.patch Magnifier (1.79 KB) Yuichi HARADA, 2020-10-13 09:13

fixed-34108-v2.patch Magnifier (3.93 KB) Yuichi HARADA, 2020-10-14 07:49

History

#1 Updated by Yuichi HARADA 13 days ago

I made the following patch with reference to the modification of #27663 .

diff --git a/app/models/issue_relation.rb b/app/models/issue_relation.rb
index d0a66ba40..e0075cb0a 100644
--- a/app/models/issue_relation.rb
+++ b/app/models/issue_relation.rb
@@ -239,6 +239,10 @@ class IssueRelation < ActiveRecord::Base
       issue_from.blocks? issue_to
     when 'blocks'
       issue_to.blocks? issue_from
+    when 'duplicated'
+      self.class.where(issue_from_id: issue_from, issue_to_id: issue_to, relation_type: TYPE_DUPLICATES).exists?
+    when 'duplicates'
+      self.class.where(issue_from_id: issue_to, issue_to_id: issue_from, relation_type: TYPE_DUPLICATES).exists?
     when 'relates'
       self.class.where(issue_from_id: issue_to, issue_to_id: issue_from).present?
     else

#2 Updated by Yuichi HARADA 12 days ago

The registration data may contain Issues that you have already circular dependency. To solve this, add the following patch to fixed-34108.patch .

diff --git a/app/models/issue.rb b/app/models/issue.rb
index 8c3146137..21aed394b 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -1848,6 +1848,14 @@ class Issue < ActiveRecord::Base
   # Closes duplicates if the issue is being closed
   def close_duplicates
     if Setting.close_duplicate_issues? && closing?
+      # Check that there are no circular dependency of relationships
+      relations_to.where(:relation_type => IssueRelation::TYPE_DUPLICATES).each do |relation|
+        unless relation.valid?
+          errors.add :base, relation.errors.full_messages.first
+          throw :abort
+        end
+      end
+
       duplicates.each do |duplicate|
         # Reload is needed in case the duplicate was updated by a previous duplicate
         duplicate.reload

#3 Updated by Go MAEDA 11 days ago

  • Target version set to Candidate for next minor release

Also available in: Atom PDF