Regression problems in Easy-PC - UPDATE: Have conformance test that triggers reference counting bug in ole32.dll

Dr J A Gow J.A.Gow at furrybubble.co.uk
Wed Feb 8 13:37:16 CST 2006


Hello All,

I wrote this some time ago:

Dr J A Gow wrote:
> Hello All,
> 
> I have some regression problems relating to Wine in a commercial ECAD 
> app 'Easy-PC' version 9.0, available from http://www.numberone.com
> 

Since then I have been doing some more digging into the problem and have 
come up with a test that triggers the bugs: i.e. passes on Windows and 
fails on Wine (latest CVS). Looking at the failure mode I feel that it 
has the potential to break a _lot_ of apps.

It is as I thought that there is some issue with the object destructor 
for the storage object being called and not actually releasing the 
object. I have attached the complete patch to the tests for storage32 to 
this message if anyone could try it I would be grateful, but I will just 
describe some of the reasoning behind it first.

It seems that the problem is not the grfMode with which the file is 
opened, but a reference counting method used within storage32. A call to 
the destructor of the storage object is not destroying the object - with 
it left open the error appears when a subsequent call to open the 
storage object fails with access issues because the previous one is left 
open. So, I introduced this test that exactly mimics the behaviour of 
the app. To do this, I needed a storage object that contained a stream, 
so I wrote code in the appropriate conformance test module to create one:


     r = StgOpenStorage( filename, NULL, STGM_TRANSACTED | STGM_WRITE | 
STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
     ok(r==S_OK, "StgOpenStorage failed\n");
     if(stg)
     {
         static const WCHAR stmname[] =  { 
'w','i','n','e','t','e','s','t',0};
         IStream *stm = NULL;

         r = IStorage_CreateStream( stg, stmname, STGM_WRITE | 
STGM_SHARE_EXCLUSIVE,
                                    0, 0, &stm );
         ok(r == S_OK, "CreateStream should succeed\n");

		if(stm) {
			r=IStorage_Commit(stg,STGC_DEFAULT);
		    ok(r==S_OK, "StorageCommit failed\n");

		}

		// Windows reference counting seems different....

         r = IStorage_Release(stg);
         ok(r == 0, "wrong ref count"); printf("- ref count = %lx\n",r);

		if(r) {
	        r = IStorage_Release(stg);
     	    ok(r == 0, "wrong ref count"); printf(" - ref count = %lx\n",r);
		}

     }

It was here where I got the surprise! I expected this code to work on 
both Wine and Windows, so the next part of the patch could trigger the 
bug. However I found that on Windows, the first call to IStorage_Release 
returns zero, and the storage object is destroyed. Under Wine however, 
the first call to IStorage_Release returns 1 but does not destroy the 
object - the second call to IStorage_Release returns zero and destroys 
the object. It appears that Windows takes no notice of reference counts 
when the IStorage destructor is called! I only discovered this because 
in the original test code I had two calls to IStorage_Release straight 
after each other without the if(r) test: and although it worked on Wine 
it segfaulted on Windows due to the 'stg' object being destroyed on the 
first call. This proved the difference in behaviour.

Now on to the second part of the test, that attempted to re-open the 
closed storage object, then open the stream within it:



     /* Easy-PC test 2 - this looks for the OpenStream mode check. Fails 
under Wine */

     r = StgOpenStorage( filename, NULL, 0x00010020, NULL, 0, &stg);
     ok(r==S_OK, "StgOpenStorage failed\n");
     if(stg)
     {
         static const WCHAR stmname[] =  { 
'w','i','n','e','t','e','s','t',0};
         IStream *stm = NULL;

         r = IStorage_OpenStream( stg, stmname, 0, 
STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
         ok(r == S_OK, "OpenStream should succeed - "); printf("rc from 
OpenStream : %lx\n",r);

         r = IStorage_Release(stg);
         ok(r == 0, "wrong ref count\n");
     }

Again, this works on Windows, but the OpenStream call fails with an 
access denied error on Wine. This is the exact mode of the bug in the app.

Could one of the ole32 developers please contact me: I am happy to work 
with them to resolve this problem as I need this app to work under Wine, 
but not being a Windows programmer I am not fully familiar with the 
storage API. In the meantime I will continue my investigation and see if 
I can fix this directly, but I am sure it will happen sooner if I could 
work with the ole32 developer.

Many thanks for listening. The patch is below, I will submit this for 
inclusion in CVS.

	John.


Index: wine/dlls/ole32/tests/storage32.c
===================================================================
RCS file: /home/wine/wine/dlls/ole32/tests/storage32.c,v
retrieving revision 1.14
diff -u -p -r1.14 storage32.c
--- wine/dlls/ole32/tests/storage32.c	6 Oct 2005 11:38:45 -0000	1.14
+++ wine/dlls/ole32/tests/storage32.c	8 Feb 2006 18:17:03 -0000
@@ -448,6 +448,77 @@ static void test_open_storage(void)
          ok(r == 0, "wrong ref count\n");
      }

+
+
+	//
+	// EASY-PC TESTS
+	//
+	// There are two bugs related to Wine and Easy-PC. This pair of tests
+	// triggers the first of the two.
+	//
+	// These tests trigger the same bug in Wine that Easy-PC does. They:
+	//
+	// 1) Open a storage file, write a stream to it, commit it and then close
+	//    the file. This is just so we have a storage file with a stream in
+	//	  it. This operation itself does not trigger the bug.
+	//
+	// 2) It then performs the action that triggers the bug. It opens the
+	//    storage file with a grfMode of 0x00010020
+	//    (STGM_TRANSACTED|STGM_READ|STGM_SHARE_DENY_WRITE). It then opens
+	//    a stream in the file with a grfMode of 
STGM_SHARE_EXCLUSIVE|STGM_READWRITE
+	//    This test works under Windows, but fails under Wine.
+
+
+    /* Easy-PC bug test 1 - this Creates a stream within an object and 
should not fail*/
+
+    r = StgOpenStorage( filename, NULL, STGM_TRANSACTED | STGM_WRITE | 
STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
+    ok(r==S_OK, "StgOpenStorage failed\n");
+    if(stg)
+    {
+        static const WCHAR stmname[] =  { 
'w','i','n','e','t','e','s','t',0};
+        IStream *stm = NULL;
+
+        r = IStorage_CreateStream( stg, stmname, STGM_WRITE | 
STGM_SHARE_EXCLUSIVE,
+                                   0, 0, &stm );
+        ok(r == S_OK, "CreateStream should succeed\n");
+
+		if(stm) {
+			r=IStorage_Commit(stg,STGC_DEFAULT);
+		    ok(r==S_OK, "StorageCommit failed\n");
+
+		}
+
+		// Windows reference counting seems different....
+
+        r = IStorage_Release(stg);
+        ok(r == 0, "wrong ref count"); printf("- ref count = %lx\n",r);
+
+		if(r) {
+	        r = IStorage_Release(stg);
+    	    ok(r == 0, "wrong ref count"); printf(" - ref count = %lx\n",r);
+		}
+
+    }
+
+    /* Easy-PC test 2 - this looks for the OpenStream mode check. Fails 
under Wine */
+
+    r = StgOpenStorage( filename, NULL, 0x00010020, NULL, 0, &stg);
+    ok(r==S_OK, "StgOpenStorage failed\n");
+    if(stg)
+    {
+        static const WCHAR stmname[] =  { 
'w','i','n','e','t','e','s','t',0};
+        IStream *stm = NULL;
+
+        r = IStorage_OpenStream( stg, stmname, 0, 
STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stm );
+        ok(r == S_OK, "OpenStream should succeed - "); printf("rc from 
OpenStream : %lx\n",r);
+
+        r = IStorage_Release(stg);
+        ok(r == 0, "wrong ref count\n");
+    }
+
+	//
+	// End of Easy-PC bug test.
+
      r = DeleteFileW(filename);
      ok(r, "file didn't exist\n");
  }





More information about the wine-devel mailing list