MapViewOfFile引起的问题。。。 (续)

前一遍说到了为什么访问内存会越界,以及我们是如何找到根本原因的。

在知道为什么有越界访问之后,我们下一个问题是:为什么第一次调用mapviewoffile会失败?为什么第二次调用mapviewoffile会成功了?

查阅了msdn一下。如果在调用MapViewOfFile()的时候,dwNumberOfBytesToMap如果大于文件的size,那么该call就会失败,并且error code是access denied。

这个解释貌似和我们发生的很贴切。因为第一次size太大了,第一次就会失败。但是如果第二次我们指明map到文件末尾,那么就会成功。

但是,我们审阅了我们的代码后,觉得不会发生这样的情况。size是根据文件信息读出来的,因而不会有错。

那会是什么引起的了?

因为message会不断的增加,所以message writer会check当前的buffer有没有写完。如果快写完了,那么就flush当前的view,close当前的handle。然后调用createmappingfile(),创建一个更大的MMF。同时为给这块shared memory取一个新的名字。

会不会是message reader这边用错了handle了?

看一下handle的information。

0:000> !handle 0x00000cb0  f
Handle 00000cb0
  Type             Section
  Attributes       0
  GrantedAccess    0x4:
         None
         MapRead
  HandleCount      2
  PointerCount     4
  Name             \BaseNamedObjects\3835699D-D3CE-4847-BFCA-A50791DF408D_Log_FileMap10

最后的数字,10,是writer新取的instance number。这个数字很蹊跷,因为应该不会这么大。

看一下实际上应该是多少。

0:000> dt _HeaderLogMessageInfoStruct 0x04dbb6e8+0x05c
MsgMMFReader!_HeaderLogMessageInfoStruct
   +0x000 NumberOfRecords  : 0x5112
   +0x004 WriteNewLogRecordOffset : 0x260070
   +0x008 WriteNewRecordIntoBlobOffset : 0x284719
   +0x00c SizeOfLogMMFFile : 0x2a0000
   +0x010 SizeOfDataMMFFile : 0x2a0000
   +0x014 CurrentLogMappingNumberInWriter : 2
   +0x018 CurrentBlobMappingNumberInWriter : 1
   +0x01c UnreadInfoMsgCnt : 0xfffffe1d
   +0x020 UnreadWarningMsgCnt : 0x122b
   +0x024 UnreadErrorMsgCnt : 0x21f
   +0x028 TotalInfoMsgsCount : 5469
   +0x02c TotalWarningMsgsCount : 4651
   +0x030 TotalErrorMsgsCount : 853
   +0x034 InformationMsgsViewed : 0
   +0x035 WarningMsgsViewed : 0
   +0x036 ErrorMsgsViewed  : 0
   +0x038 FirstRecIn24HourWindow : 0x2636
   +0x03c FileCreationTimeStamp : _SYSTEMTIME
   +0x04c LastTouchTimeStamp : _SYSTEMTIME

我们看到,Writer那边的instance number才是2。而reader那边居然用的是10。这才是导致MapViewOfFIle失败的真正原因。

又重新看了遍code。发现代码那边有check number change scenario。但是,代码是这么写的:

if (m_currentLogMappingNumber < m_msgLogHeaderStruct.CurrentLogMappingNumberInWriter)
{
// remap the mmf
}

这个地方用的是比较大小来决定需不需要重新mapviewoffile。这个才是真真正正的root cause! 应该用“!=”来判断!

把这个地方改为"!="后,这个问题再也没有重现过。

原文地址:https://www.cnblogs.com/xiaxi/p/2027219.html