Aspose Words can generate stack overflows when processing merge fields

Hi,

When using Aspose Words to process merge fields, I came across this one case where a stack overflow exception would take place.

I have been able to create a simple sandbox application which can reproduce this error. The issue appears when the field value is set to the name of merge field, see the code for more details. Along with the code provided I have included two templates, firstly a basic Word template which behaves fine and secondly a Word template that leads to the stack overflow.

Using DebugDiag and WinDbg tools to get the stack traces from the dump, I have a high degree of confidence that the stack overflow is in the Aspose code. I have included the full stack trace in the attachment, yet here is a sample.

0000000000ca76b8 000007f991fbe3f7 [InlinedCallFrame: 0000000000ca76b8] System.Globalization.CompareInfo.InternalGetGlobalizedHashCode(IntPtr, IntPtr, System.String, System.String, Int32, Int32, Boolean, Int64)
0000000000ca76b8 000007f980cfc5e0 [InlinedCallFrame: 0000000000ca76b8] System.Globalization.CompareInfo.InternalGetGlobalizedHashCode(IntPtr, IntPtr, System.String, System.String, Int32, Int32, Boolean, Int64)
0000000000ca7670 000007f980cfc5e0 *** WARNING: Unable to verify checksum for mscorlib.ni.dll
DomainNeutralILStubClass.IL_STUB_PInvoke(IntPtr, IntPtr, System.String, System.String, Int32, Int32, Boolean, Int64)
0000000000ca7780 000007f980c10cae System.Globalization.CompareInfo.GetHashCodeOfString(System.String, System.Globalization.CompareOptions, Boolean, Int64)
0000000000ca77e0 000007f980c10bd5 System.Globalization.CompareInfo.GetHashCodeOfString(System.String, System.Globalization.CompareOptions)
0000000000ca7820 000007f980c7773c System.Collections.Hashtable.get_Item(System.Object)
0000000000ca78d0 000007f923621f5f *** WARNING: Unable to verify checksum for Aspose.Words.dll
ERROR: Module load completed but symbols could not be loaded for Aspose.Words.dll
xfbd1009a0cbb9842.xfedf115fd9c03862.x87c729ecf87183e5(Aspose.Words.DocumentBase, System.String)
0000000000ca7940 000007f923621a3a x2a6f63b6650e76c4.xb42dd4742eae5750.x3494e22b9d135f56(x2a6f63b6650e76c4.xa7ef704c7557cbae)
0000000000ca79a0 000007f9236219bc x2a6f63b6650e76c4.xc4d9903a188c1793.xb1de1ba20faeeff8(x2a6f63b6650e76c4.x496b40ebe5ff5626)
 0000000000ca79f0 000007f923621b5c x2a6f63b6650e76c4.xb42dd4742eae5750.x3494e22b9d135f56(x2a6f63b6650e76c4.xa7ef704c7557cbae)
0000000000ca7a50 000007f9236219bc x2a6f63b6650e76c4.xc4d9903a188c1793.xb1de1ba20faeeff8(x2a6f63b6650e76c4.x496b40ebe5ff5626)
0000000000ca7aa0 000007f923621b5c x2a6f63b6650e76c4.xb42dd4742eae5750.x3494e22b9d135f56(x2a6f63b6650e76c4.xa7ef704c7557cbae)
0000000000d9e6a0 000007f9236219bc x2a6f63b6650e76c4.xc4d9903a188c1793.xb1de1ba20faeeff8(x2a6f63b6650e76c4.x496b40ebe5ff5626)
0000000000d9e6f0 000007f923621b5c x2a6f63b6650e76c4.xb42dd4742eae5750.x3494e22b9d135f56(x2a6f63b6650e76c4.xa7ef704c7557cbae)
0000000000d9e750 000007f9236219bc x2a6f63b6650e76c4.xc4d9903a188c1793.xb1de1ba20faeeff8(x2a6f63b6650e76c4.x496b40ebe5ff5626)
0000000000d9e7a0 000007f92361f6f1 x2a6f63b6650e76c4.xa4690fb61715fc9b.x335c6a74b612cfe6(Aspose.Words.Fields.Field, x2a6f63b6650e76c4.x6f82c326b827643c)
0000000000d9e810 000007f92361f4e2 xfbd1009a0cbb9842.xedefa1db6f5ff538.xfcc1c57a5276ff93()
24: 0000000000d9e850 000007f923619beb Aspose.Words.Fields.Field.x0b575d343c8e4df3()
0000000000d9e880 000007f923618eb5 Aspose.Words.Fields.Field.x42a25ae95099edb8(xfbd1009a0cbb9842.x5e36356bc92c609b)
0000000000d9e8e0 000007f923618a89 Aspose.Words.Fields.Field.x295cb4a1df7a5add(xfbd1009a0cbb9842.x5e36356bc92c609b)
0000000000d9e950 000007f923618578 xfbd1009a0cbb9842.xfedf115fd9c03862.x4e3cfc222c92cda7(Aspose.Words.Fields.Field, xfbd1009a0cbb9842.x5e36356bc92c609b)
0000000000d9e9d0 000007f923618222 xfbd1009a0cbb9842.xbf9ddf72e1283af9.x18dfca7c5fd2402f()
0000000000d9ea40 000007f923618054 xfbd1009a0cbb9842.xfedf115fd9c03862.xdd6cf0348a23f220(xfbd1009a0cbb9842.xcf417e2db4fe9ed3)
0000000000d9eaa0 000007f923617efc xfbd1009a0cbb9842.xfedf115fd9c03862.xdf269951086089ce(xfbd1009a0cbb9842.x864e471e9e1ff2b4)
0000000000d9eb10 000007f923611b2d xe86f37adaccef1c3.xc5c3f438428cb03b.xdeeb682062ef79a5()
0000000000d9eb70 000007f923611a06 xe86f37adaccef1c3.xc5c3f438428cb03b.xd5da23b762ce52a2(xe86f37adaccef1c3.xa11a4c48b53f49a6, Boolean)
0000000000d9ebb0 000007f92361062c Aspose.Words.Reporting.MailMerge.x18dfca7c5fd2402f(xe86f37adaccef1c3.xa11a4c48b53f49a6)
0000000000d9ec00 000007f923520383 *** WARNING: Unable to verify checksum for AsposeSandbox.exe

By trial and error, I have found that the stack overflow does not occur if lines 24 and 28 are commented out (the bookmark code) - see below.

using Aspose.Words;
using Aspose.Words.Reporting;
      
namespace AsposeSandbox
{
    public class FieldMerger : IFieldMergingCallback
    {
        public void FieldMerging(FieldMergingArgs args)
        {
            var builder = new DocumentBuilder(args.Document);
            args.Text = "";

            if (!builder.MoveToMergeField(args.FieldName, true, true))
            {
                // merge field does not exist
                return;
            }

            var text = (string)args.FieldValue;
            text = text ?? "";

            var bookmarkedName = args.FieldName;

            builder.StartBookmark(bookmarkedName);

            builder.Write(text);

            builder.EndBookmark(bookmarkedName);
        }

        public void ImageFieldMerging(ImageFieldMergingArgs args)
        {
            // no op
        }
    }
}

Regards,

Matthew

Hi Matthew,

Thanks for your inquiry. In your case, I suggest you please use the last argument value as ‘false’ in MoveToMergeField method as shown below. This will solve the exception issue.

if (!builder.MoveToMergeField(args.FieldName, true, false))
{
    // merge field does not exist
    return;
}

In your code, you are inserting bookmarks with same name of mail merge fields. Please note that Aspose.Words tries to mimic the same behaviour as MS Word do. MS Word allows only unique names for bookmarks. If you change the name of a bookmark to a name that already exists in the document, no error will be given and only the first bookmark will be stored when you save the document.