0029669: Crash on opening a document with same Ocaf attributes with different IDs
authorabv <abv@opencascade.com>
Fri, 25 May 2018 18:26:45 +0000 (21:26 +0300)
committerabv <abv@opencascade.com>
Fri, 25 May 2018 18:55:00 +0000 (21:55 +0300)
Added protection against clash of attributes with the same GUID when more than one attribute of the same type but with different GUIDs are stored in the file.
If attribute with default GUID has already been read, then adding next empty attribute of the same type (done at start of its reading) will fail; in such case another attempt is made with Null GUID.

src/BinLDrivers/BinLDrivers_DocumentRetrievalDriver.cxx
src/XmlMDF/XmlMDF.cxx
tests/bugs/caf/bug29669 [new file with mode: 0644]

index 54d45b6..434a971 100644 (file)
@@ -358,8 +358,24 @@ Standard_Integer BinLDrivers_DocumentRetrievalDriver::ReadSubTree
         tAtt = Handle(TDF_Attribute)::DownCast(myRelocTable.Find(anID));
       else
         tAtt = aDriver->NewEmpty();
+
       if (tAtt->Label().IsNull())
-        theLabel.AddAttribute (tAtt);
+      {
+        try
+        {
+          theLabel.AddAttribute (tAtt);
+        }
+        catch (const Standard_DomainError&)
+        {
+          // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
+          // will be raised in valid case if attribute of that type with default GUID is already
+          // present  on the same label; the reason is that actual GUID will be read later.
+          // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
+          static const Standard_GUID fbidGuid;
+          tAtt->SetID (fbidGuid);
+          theLabel.AddAttribute (tAtt);
+        }
+      }
       else
         myMsgDriver->Send (aMethStr +
                      "warning: attempt to attach attribute " +
index dd6588e..da52376 100644 (file)
@@ -36,6 +36,7 @@
 #include <XmlLDrivers.hxx>
 #include <TDocStd_Owner.hxx>
 #include <TDocStd_Document.hxx>
+#include <Standard_GUID.hxx>
 
 IMPLEMENT_DOMSTRING (TagString,         "tag")
 IMPLEMENT_DOMSTRING (LabelString,       "label")
@@ -257,8 +258,24 @@ Standard_Integer XmlMDF::ReadSubTree (const XmlObjMgt_Element&    theElement,
             tAtt = Handle(TDF_Attribute)::DownCast(theRelocTable.Find(anID));
           else
             tAtt = driver -> NewEmpty();
-         if (tAtt->Label().IsNull())
-           theLabel.AddAttribute (tAtt);
+
+          if (tAtt->Label().IsNull())
+          {
+            try
+            {
+              theLabel.AddAttribute (tAtt);
+            }
+            catch (const Standard_DomainError&)
+            {
+              // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
+              // will be raised in valid case if attribute of that type with default GUID is already
+              // present  on the same label; the reason is that actual GUID will be read later.
+              // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
+              static const Standard_GUID fbidGuid;
+              tAtt->SetID (fbidGuid);
+              theLabel.AddAttribute (tAtt);
+            }
+          }
          else
            driver->myMessageDriver->Send
              (TCollection_ExtendedString("XmlDriver warning: ") +
diff --git a/tests/bugs/caf/bug29669 b/tests/bugs/caf/bug29669
new file mode 100644 (file)
index 0000000..be0c470
--- /dev/null
@@ -0,0 +1,41 @@
+puts " =================================================================== "
+puts " 0029669: Crash on opening a document with same Ocaf attributes with different IDs"
+puts " =================================================================== "
+puts ""
+
+set aLabel 0:1
+
+set aVal1 123
+set aVal2 321
+
+set aGuid1 "12e94541-6dbc-11d4-b9c8-0060b0ee281b"
+set aGuid2 "12e94541-6dbc-11d4-b9c8-0060b0ee281d"
+
+foreach format {{XmlOcaf xml} {BinOcaf cbf}} {
+
+  NewDocument D [lindex $format 0]
+
+  SetInteger D $aLabel $aVal1 $aGuid1
+  SetInteger D $aLabel 100
+  SetInteger D $aLabel $aVal2 $aGuid2
+
+  set aFile ${imagedir}/${casename}.[lindex $format 1]
+  SaveAs D $aFile
+  Close D
+
+  if { ! [file exists $aFile] } {
+    puts "Error: cannot find file $aFile, document not saved"
+  }
+
+  Open $aFile D
+  set val1 [GetInteger D $aLabel $aGuid1]
+  set val2 [GetInteger D $aLabel $aGuid2]
+  if { $val1 != $aVal1 } {
+    puts "Error: found $val1 while expected $aVal1"
+  }
+  if { $val2 != $aVal2 } {
+    puts "Error: found $val2 while expected $aVal2"
+  }
+  Close D
+}