[1/5] ole32: Test the entire range lock block for synchronization.

Vincent Povirk madewokherd at gmail.com
Tue Mar 10 16:29:26 CDT 2015


This series addresses bug 37202, which was a regression caused by the
storage synchronization work, where Word would hang indefinitely if
someone (LibreOffice) had the entire file range-locked for writing.

The Windows storage implementation seems to fail in about 20 seconds
at most if it can't get a lock, which I was apparently not patient
enough to discover in my initial testing.

Word on Windows can detect when an entire file is range-locked for
writing and give up within a few seconds, but I wasn't able to figure
out how it does this. I've come up with a way to detect this that I
don't expect to cause any problems when combined with the Windows
implementation, but I have no particular reason to believe it's
accurate to Windows behavior.

This test exists to verify that read-locking bytes 0x7ffffe00-ff,
which are in the reserved "range lock block" but not explicitly
reserved for locking by the standard, isn't going to cause problems
for the Windows implementation.
-------------- next part --------------
From 6f4cdab3c56aabc3bcefba88b968193915d81f2e Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Tue, 10 Mar 2015 14:29:17 -0500
Subject: [PATCH 1/5] ole32: Test the entire range lock block for
 synchronization.

---
 dlls/ole32/storage32.h       |  7 +++++--
 dlls/ole32/tests/storage32.c | 45 +++++++++++++++++++++++---------------------
 2 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/dlls/ole32/storage32.h b/dlls/ole32/storage32.h
index 9831a27..a49add9 100644
--- a/dlls/ole32/storage32.h
+++ b/dlls/ole32/storage32.h
@@ -505,7 +505,10 @@ StgStreamImpl* StgStreamImpl_Construct(
 /* Range lock constants.
  *
  * The storage format reserves the region from 0x7fffff00-0x7fffffff for
- * locking and synchronization. Unfortunately, the spec doesn't say which bytes
+ * locking and synchronization. Because it reserves the entire block containing
+ * that range, and the minimum block size is 512 bytes, 0x7ffffe00-0x7ffffeff
+ * also cannot be used for any other purpose.
+ * Unfortunately, the spec doesn't say which bytes
  * within that range are used, and for what. These are guesses based on testing.
  * In particular, ends of ranges may be wrong.
 
@@ -524,7 +527,7 @@ StgStreamImpl* StgStreamImpl_Construct(
  0xe2 through 0xff: Unknown. Causes read-only exclusive opens to fail.
 */
 
-#define RANGELOCK_UNK1_FIRST            0x7fffff00
+#define RANGELOCK_UNK1_FIRST            0x7ffffe00
 #define RANGELOCK_UNK1_LAST             0x7fffff57
 #define RANGELOCK_PRIORITY1_FIRST       0x7fffff58
 #define RANGELOCK_PRIORITY1_LAST        0x7fffff6b
diff --git a/dlls/ole32/tests/storage32.c b/dlls/ole32/tests/storage32.c
index a373249..e83ae2a 100644
--- a/dlls/ole32/tests/storage32.c
+++ b/dlls/ole32/tests/storage32.c
@@ -3153,22 +3153,22 @@ struct lock_test
     BOOL todo;
 };
 
-static const int priority_locked_bytes[] = { 0x58, 0x81, 0x93, -1 };
-static const int rwex_locked_bytes[] = { 0x93, 0xa7, 0xbb, 0xcf, -1 };
-static const int rw_locked_bytes[] = { 0x93, 0xa7, -1 };
-static const int nosn_locked_bytes[] = { 0x6c, 0x93, 0xa7, 0xcf, -1 };
-static const int rwdw_locked_bytes[] = { 0x93, 0xa7, 0xcf, -1 };
-static const int wodw_locked_bytes[] = { 0xa7, 0xcf, -1 };
-static const int tr_locked_bytes[] = { 0x93, -1 };
+static const int priority_locked_bytes[] = { 0x158, 0x181, 0x193, -1 };
+static const int rwex_locked_bytes[] = { 0x193, 0x1a7, 0x1bb, 0x1cf, -1 };
+static const int rw_locked_bytes[] = { 0x193, 0x1a7, -1 };
+static const int nosn_locked_bytes[] = { 0x16c, 0x193, 0x1a7, 0x1cf, -1 };
+static const int rwdw_locked_bytes[] = { 0x193, 0x1a7, 0x1cf, -1 };
+static const int wodw_locked_bytes[] = { 0x1a7, 0x1cf, -1 };
+static const int tr_locked_bytes[] = { 0x193, -1 };
 static const int no_locked_bytes[] = { -1 };
-static const int roex_locked_bytes[] = { 0x93, 0xbb, 0xcf, -1 };
-
-static const int rwex_fail_ranges[] = { 0x93,0xe3, -1 };
-static const int rw_fail_ranges[] = { 0xbb,0xe3, -1 };
-static const int rwdw_fail_ranges[] = { 0xa7,0xe3, -1 };
-static const int dw_fail_ranges[] = { 0xa7,0xcf, -1 };
-static const int tr_fail_ranges[] = { 0xbb,0xcf, -1 };
-static const int pr_fail_ranges[] = { 0x80,0x81, 0xbb,0xcf, -1 };
+static const int roex_locked_bytes[] = { 0x193, 0x1bb, 0x1cf, -1 };
+
+static const int rwex_fail_ranges[] = { 0x193,0x1e3, -1 };
+static const int rw_fail_ranges[] = { 0x1bb,0x1e3, -1 };
+static const int rwdw_fail_ranges[] = { 0x1a7,0x1e3, -1 };
+static const int dw_fail_ranges[] = { 0x1a7,0x1cf, -1 };
+static const int tr_fail_ranges[] = { 0x1bb,0x1cf, -1 };
+static const int pr_fail_ranges[] = { 0x180,0x181, 0x1bb,0x1cf, -1 };
 static const int roex_fail_ranges[] = { 0x0,-1 };
 
 static const struct lock_test lock_tests[] = {
@@ -3313,7 +3313,7 @@ static void test_locking(void)
             ol.u.s.OffsetHigh = 0;
             ol.hEvent = NULL;
 
-            for (ol.u.s.Offset = 0x7fffff00; ol.u.s.Offset != 0x80000000; ol.u.s.Offset++)
+            for (ol.u.s.Offset = 0x7ffffe00; ol.u.s.Offset != 0x80000000; ol.u.s.Offset++)
             {
                 if (LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ol))
                     locked = FALSE;
@@ -3325,7 +3325,7 @@ static void test_locking(void)
 
                 UnlockFileEx(hfile, 0, 1, 0, &ol);
 
-                if ((ol.u.s.Offset&0xff) == *next_lock)
+                if ((ol.u.s.Offset&0x1ff) == *next_lock)
                 {
                     expect_locked = TRUE;
                     next_lock++;
@@ -3362,14 +3362,17 @@ static void test_locking(void)
             ol.u.s.OffsetHigh = 0;
             ol.hEvent = NULL;
 
-            for (ol.u.s.Offset = 0x7fffff00; ol.u.s.Offset != 0x80000000; ol.u.s.Offset++)
+            for (ol.u.s.Offset = 0x7ffffe00; ol.u.s.Offset != 0x80000000; ol.u.s.Offset++)
             {
                 if (ol.u.s.Offset == 0x7fffff92 ||
                     (ol.u.s.Offset == 0x7fffff80 && current->stg_mode == (STGM_TRANSACTED|STGM_READWRITE)) ||
                     (ol.u.s.Offset == 0x7fffff80 && current->stg_mode == (STGM_TRANSACTED|STGM_READ)))
                     continue; /* This makes opens hang */
 
-                LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ol);
+                if (ol.u.s.Offset < 0x7fffff00)
+                    LockFileEx(hfile, 0, 0, 1, 0, &ol);
+                else
+                    LockFileEx(hfile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ol);
 
                 hr = StgOpenStorage(filename, NULL, current->stg_mode, NULL, 0, &stg);
                 ok(hr == S_OK || hr == STG_E_LOCKVIOLATION || hr == STG_E_SHAREVIOLATION, "failed with unexpected hr %x\n", hr);
@@ -3379,11 +3382,11 @@ static void test_locking(void)
 
                 failed = FAILED(hr);
 
-                if (!expect_failed && (ol.u.s.Offset&0xff) == next_range[0])
+                if (!expect_failed && (ol.u.s.Offset&0x1ff) == next_range[0])
                 {
                     expect_failed = TRUE;
                 }
-                else if (expect_failed && (ol.u.s.Offset&0xff) == next_range[1])
+                else if (expect_failed && (ol.u.s.Offset&0x1ff) == next_range[1])
                 {
                     expect_failed = FALSE;
                     next_range += 2;
-- 
2.1.0



More information about the wine-patches mailing list