Strange problem calling .DLL from C #

I am trying to call the htmlTidy library dll from C #. There are a few examples floating around the net, but nothing definitive ... and I have no problems whatsoever. I'm pretty sure the problem is with the p / invoke declaration ... but changed if I know where I'm going wrong.

I got libtidy.dll from http://www.paehl.com/open_source/?HTML_Tidy_for_Windows which seems to be the current version.

Here's a console app demonstrating the problem I'm running into:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApplication5
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct TidyBuffer
        {
            public IntPtr bp;         // Pointer to bytes
            public uint size;         // # bytes currently in use
            public uint allocated;    // # bytes allocated
            public uint next;         // Offset of current input position
        };

        [DllImport("libtidy.dll")]
        public static extern int tidyBufAlloc(ref TidyBuffer tidyBuffer, uint allocSize);


        static void Main(string[] args)
        {
            Console.WriteLine(CleanHtml("<html><body><p>Hello World!</p></body></html>"));
        }

        static string CleanHtml(string inputHtml)
        {
            byte[] inputArray = Encoding.UTF8.GetBytes(inputHtml);
            byte[] inputArray2 = Encoding.UTF8.GetBytes(inputHtml);

            TidyBuffer tidyBuffer2;
            tidyBuffer2.size = 0;
            tidyBuffer2.allocated = 0;
            tidyBuffer2.next = 0;
            tidyBuffer2.bp = IntPtr.Zero;

            //
            // tidyBufAlloc overwrites inputArray2... why? how? seems like
            // tidyBufAlloc is stomping on the stack a bit too much... but
            // how? I've tried changing the calling convention to cdecl and
            // stdcall but no change.
            //
            Console.WriteLine((inputArray2 == null ? "Array2 null" : "Array2 not null"));
            tidyBufAlloc(ref tidyBuffer2, 65535);
            Console.WriteLine((inputArray2 == null ? "Array2 null" : "Array2 not null"));
            return "did nothing";
        }
    }
}

      

In general, I'm a little upset. Any help would be appreciated!

+1


a source to share


3 answers


You are working with the old definition of the TidyBuffer structure. The new structure is larger, so when you call the allocate method, it overwrites the stack location for inputArray2. New definition:



    [StructLayout(LayoutKind.Sequential)]        
    public struct TidyBuffer        
    {
        public IntPtr allocator;  // Pointer to custom allocator            
        public IntPtr bp;         // Pointer to bytes            
        public uint size;         // # bytes currently in use            
        public uint allocated;    // # bytes allocated            
        public uint next;         // Offset of current input position        
    };        

      

+3


a source


For what it's worth, we tried Tidy at work and switched to HtmlAgilityPack.



+2


a source


Try changing your tidyBufAlloc declaration to:

[DllImport("libtidy.dll", CharSet = CharSet.Ansi)]
private static extern int tidyBufAlloc(ref TidyBuffer Buffer, int allocSize);

      

Notice the addition of CharSet.Ansi and "int allocSize" (instead of uint).

Also, see this sample code for an example of using HTML Tidy in C #.

In your example, if inputHTML is large, say 50K, inputArray and inputArray2 will be 50K each as well.

Then you also try to allocate 65K in the tidyBufAlloc call.

If the pointer is not initialized correctly, it is very possible that a random .NET mailing address is being used. Hence, part or all of the seemingly unrelated variable / buffer is being overwritten. It's just luck, or that you've already allocated large buffers, that you're not rewriting a block of code that is likely to cause an invalid memory access error.

0


a source







All Articles