
win10企业版 _MBCS
MFC42!CString::SetAt: CFG 73d87f28 56 push esi 73d87f29 8bf1 mov esi, ecx 73d87f2b e8f9a7faff call MFC42!CString::CopyBeforeWrite (73d32729) 73d87f30 8b06 mov eax, dword ptr [esi] 73d87f32 8a4c240c mov cl, byte ptr [esp+0Ch] 73d87f36 8b542408 mov edx, dword ptr [esp+8] 73d87f3a 880c02 mov byte ptr [edx+eax], cl 73d87f3d 5e pop esi 73d87f3e c20800 ret 8
0:000> lmDvmMFC42 Browse full module list start end module name 73d30000 73e21000 MFC42 (pdb symbols) C:\ProgramData\Dbg\sym\MFC42.pdb\B73DC11F74B24943B4DC97DE9D5A3131e\MFC42.pdb Loaded symbol image file: D:\01 Workspace_YX_HC _liul\Release\MFC42.DLL Image path: D:\01 Workspace_YX_HC _liul\Release\MFC42.DLL Image name: MFC42.DLL Browse all global symbols functions data Symbol Reload Timestamp: Sat Sep 18 14:52:55 2010 (4C9461C7) CheckSum: 000F90A3 ImageSize: 000F1000 Mapping Form: Loaded File version: 6.2.8073.0 Product version: 6.2.4.0 File flags: 0 (Mask 3F) File OS: 40004 NT Win32 File type: 2.0 Dll File date: 00000000.00000000 Translations: 0409.04e4 Information from resource tables: CompanyName: Microsoft Corporation ProductName: Microsoft (R) Visual C++ InternalName: MFCDLL OriginalFilename: MFC42.DLL ProductVersion: 6.02.400 FileVersion: 6.02.8073.0 FileDescription: MFCDLL Shared Library - Retail Version LegalCopyright: Copyright (C) Microsoft Corp. 1993-1998 LegalTrademarks:
73DFB6D4 00 00 00 00 84 9A DD 73 00 00 00 00 2E 3F //原始内存数据 ,2e9add73这个地址可能是别的对象的数据地址,当被改写后,数据就变了,如果是数据库中关键的数据就惨了,不知不觉中数据被修改了 73DFB6D4 31 39 39 30 2E 9A DD 73 00 00 00 00 2E 3F //输入1990 1 后 1990. 73DFB6D4 31 39 39 30 2E 31 32 2E 33 30 00 00 2e 3f 1990.12.30 73DFB6AC 2E 3F 41 56 43 4D 61 70 57 6F 72 64 54 6F 50 74 72 40 40 00 D4 B6 DF 73 C8 B6 DF 73 FF FF FF FF 00 00 00 00 00 00 00 00 .?AVCMapWordToPtr@@.远遱榷遱............ 73DFB6D4 31 39 39 30 2E 31 32 2E 33 30 00 00 2E 3F 41 56 43 4E 6F 54 72 61 63 6B 4F 62 6A 65 63 74 40 40 00 00 00 00 84 9A DD 73
当输入另一个日期框时,数据本来是00,后面的数据是上一个日期框的数据残留

73DFB6AC 2E 3F 41 56 43 4D 61 70 57 6F 72 64 54 6F 50 74 72 40 40 00 D4 B6 DF 73 C8 B6 DF 73 FF FF FF FF 00 00 00 00 00 00 00 00 .?AVCMapWordToPtr@@.远遱榷遱............ 73DFB6D4 [31 39 30 30 2E 30 31] 2E 33 30 00 00 2E 3F 41 56 43 4E 6F 54 72 61 63 6B 4F 62 6A 65 63 74 40 40 00 00 00 00 84 9A DD 73 //1999.01
企业版 UNICODE 版本下
m_strWindowText 被置空后,再调用 m_strWindowText.SetAt(nEndPos, static_cast<TCHAR>(nChar)); 是不行的
MFC42u!CString::SetAt: CFG 586f7b20 8bff mov edi, edi //占位指令 586f7b22 55 push ebp 586f7b23 8bec mov ebp, esp 586f7b25 56 push esi 586f7b26 8b7508 mov esi, dword ptr [ebp+8] //nIndex, 第一个参数 586f7b29 57 push edi 586f7b2a 8bf9 mov edi, ecx 586f7b2c 85f6 test esi, esi //if(nIndex < 0) 586f7b2e 781c js MFC42u!CString::SetAt+0x2c (586f7b4c) //结果sf=1,代表负值,抛出异常 586f7b30 8b07 mov eax, dword ptr [edi] 586f7b32 3b70f8 cmp esi, dword ptr [eax-8] //cstringdata , length 586f7b35 7d15 jge MFC42u!CString::SetAt+0x2c (586f7b4c) //if(nIndex >= length) throw 586f7b37 e844fcffff call MFC42u!CString::CopyBeforeWrite (586f7780) 586f7b3c 8b0f mov ecx, dword ptr [edi] 586f7b3e 668b450c mov ax, word ptr [ebp+0Ch] 586f7b42 5f pop edi 586f7b43 66890471 mov word ptr [ecx+esi*2], ax 586f7b47 5e pop esi 586f7b48 5d pop ebp 586f7b49 c20800 ret 8 586f7b4c e87f68ffff call MFC42u!AfxThrowInvalidArgException (586ee3d0) //异常,无效参数 586f7b51
void CString::SetAt(int nIndex, TCHAR ch) { ASSERT(nIndex >= 0); ASSERT(nIndex < GetData()->nDataLength); CopyBeforeWrite(); m_pchData[nIndex] = ch; }
正常的unicode 内存数据
0:000> db 0x86291f0 086291f0 00 00 00 00 01 00 00 00-0a 00 00 00 40 00 00 00 ............@... 08629200 32 00 30 00 32 00 36 00-2e 00 31 00 32 00 2e 00 2.0.2.6...1.2... 08629210 31 00 39 00 00 00 00 00-6e 00 74 00 41 00 64 00 1.9.....n.t.A.d. 08629220 64 00 72 00 49 00 6e 00-66 00 6f 00 5d 00 00 00 d.r.I.n.f.o.]... 08629230 49 00 4e 00 46 00 4f 00-5d 00 00 00 00 00 00 00 I.N.F.O.]....... 08629240 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 08629250 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 08629260 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:000> dx -r1 (*((ToolLib!CString *)0x19df44)) (*((ToolLib!CString *)0x19df44)) [Type: CString] [+0x000] m_pchData : 0x8629200 : 0x32 [Type: unsigned short *]
/
{ pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)]; pData->nAllocLength = nLen; //6 } 052E7D90 CD CD CD CD CD CD CD CD [06 00 00 00] CD CD CD CD 屯屯屯屯....屯屯 //申请长度 06 052E7DA0 CD CD CD CD CD CD CD CD CD CD FD FD FD FD 00 00 { pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)]; pData->nAllocLength = nLen; } pData->nRefs = 1; pData->data()[nLen] = '\0'; 052E7D90 [01 00 00 00] CD CD CD CD 06 00 00 00 CD CD CD CD ....屯屯....屯屯 //引用记数 01 052E7DA0 CD CD CD CD CD CD CD CD [00 00] FD FD FD FD 00 00
/
struct CStringData { long nRefs; // reference count int nDataLength; // length of data (including terminator) int nAllocLength; // length of allocation // TCHAR data[nAllocLength] TCHAR* data() // TCHAR* to managed data { return (TCHAR*)(this+1); } };
#ifndef _DEBUG
#pragma warning(disable: 4074)
#pragma init_seg(compiler) #define ROUND(x,y) (((x)+(y-1))&~(y-1)) #define ROUND4(x) ROUND(x, 4) AFX_STATIC CFixedAlloc _afxAlloc64(ROUND4(65*sizeof(TCHAR)+sizeof(CStringData))); AFX_STATIC CFixedAlloc _afxAlloc128(ROUND4(129*sizeof(TCHAR)+sizeof(CStringData))); AFX_STATIC CFixedAlloc _afxAlloc256(ROUND4(257*sizeof(TCHAR)+sizeof(CStringData))); AFX_STATIC CFixedAlloc _afxAlloc512(ROUND4(513*sizeof(TCHAR)+sizeof(CStringData)));
#endif
// fixalloc.h - declarations for fixed block allocator #ifndef __FIXALLOC_H__ #define __FIXALLOC_H__ #include "afxplex_.h" ///////////////////////////////////////////////////////////////////////////// // CFixedAlloc class CFixedAlloc { // Constructors public: CFixedAlloc(UINT nAllocSize, UINT nBlockSize = 64); // Attributes UINT GetAllocSize() { return m_nAllocSize; } // Operations public: void* Alloc(); // return a chunk of memory of nAllocSize void Free(void* p); // free chunk of memory returned from Alloc void FreeAll(); // free everything allocated from this allocator // Implementation public: ~CFixedAlloc(); protected: struct CNode { CNode* pNext; // only valid when in free list }; UINT m_nAllocSize; // size of each block from Alloc UINT m_nBlockSize; // number of blocks to get at a time CPlex* m_pBlocks; // linked list of blocks (is nBlocks*nAllocSize) CNode* m_pNodeFree; // first free node (NULL if no free nodes) CRITICAL_SECTION m_protect; }; #ifndef _DEBUG // DECLARE_FIXED_ALLOC -- used in class definition #define DECLARE_FIXED_ALLOC(class_name) \ public: \ void* operator new(size_t size) \ { \ ASSERT(size == s_alloc.GetAllocSize()); \ UNUSED(size); \ return s_alloc.Alloc(); \ } \ void* operator new(size_t, void* p) \ { return p; } \ void operator delete(void* p) { s_alloc.Free(p); } \ void* operator new(size_t size, LPCSTR, int) \ { \ ASSERT(size == s_alloc.GetAllocSize()); \ UNUSED(size); \ return s_alloc.Alloc(); \ } \ protected: \ static CFixedAlloc s_alloc \ // IMPLEMENT_FIXED_ALLOC -- used in class implementation file #define IMPLEMENT_FIXED_ALLOC(class_name, block_size) \ CFixedAlloc class_name::s_alloc(sizeof(class_name), block_size) \ #else //!_DEBUG #define DECLARE_FIXED_ALLOC(class_name) // nothing in debug #define IMPLEMENT_FIXED_ALLOC(class_name, block_size) // nothing in debug #endif //!_DEBUG #endif ///////////cpp // fixalloc.cpp - implementation of fixed block allocator #include "stdafx.h" #include "fixalloc.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif ///////////////////////////////////////////////////////////////////////////// // CFixedAlloc CFixedAlloc::CFixedAlloc(UINT nAllocSize, UINT nBlockSize) { ASSERT(nAllocSize >= sizeof(CNode)); ASSERT(nBlockSize > 1); m_nAllocSize = nAllocSize; m_nBlockSize = nBlockSize; m_pNodeFree = NULL; m_pBlocks = NULL; InitializeCriticalSection(&m_protect); } CFixedAlloc::~CFixedAlloc() { FreeAll(); DeleteCriticalSection(&m_protect); } void CFixedAlloc::FreeAll() { EnterCriticalSection(&m_protect); m_pBlocks->FreeDataChain(); m_pBlocks = NULL; m_pNodeFree = NULL; LeaveCriticalSection(&m_protect); } void* CFixedAlloc::Alloc() { EnterCriticalSection(&m_protect); if (m_pNodeFree == NULL) { CPlex* pNewBlock = NULL; TRY { // add another block pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize, m_nAllocSize); } CATCH_ALL(e) { LeaveCriticalSection(&m_protect); THROW_LAST(); } END_CATCH_ALL // chain them into free list CNode* pNode = (CNode*)pNewBlock->data(); // free in reverse order to make it easier to debug (BYTE*&)pNode += (m_nAllocSize * m_nBlockSize) - m_nAllocSize; for (int i = m_nBlockSize-1; i >= 0; i--, (BYTE*&)pNode -= m_nAllocSize) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; } } ASSERT(m_pNodeFree != NULL); // we must have something // remove the first available node from the free list void* pNode = m_pNodeFree; m_pNodeFree = m_pNodeFree->pNext; LeaveCriticalSection(&m_protect); return pNode; } void CFixedAlloc::Free(void* p) { if (p != NULL) { EnterCriticalSection(&m_protect); // simply return the node to the free list CNode* pNode = (CNode*)p; pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; LeaveCriticalSection(&m_protect); } }
这种写法 *&(更准确地说是 (Type*&)expr) 在 C++ 中虽然没有一个官方标准化的专有名称,但在程序员社区和系统编程领域中,常被称作以下几种说法: ✅ 常见称呼(非正式但广泛理解): 1. “指针的引用强制转换”(Pointer reference cast) 强调:你不是在转换指针所指向的数据,而是在把一个指针变量本身当作另一种类型的指针来重新解释,并允许修改它。 示例:(BYTE*&)pNode → “把 pNode 当作一个 BYTE* 类型的引用”。 2. “类型双关指针操作” / “指针重解释引用” 属于 type punning(类型双关) 的一种形式。 虽然严格来说 type punning 通常指通过 union 或 reinterpret_cast 访问同一内存的不同类型,但这种通过引用强制转换来改变指针算术行为的做法,也被视为一种 “指针层面的 type punning”。 3. “就地指针类型转换”(In-place pointer retyping) 强调:不创建新变量,直接在原指针变量上“临时换肤”,进行字节级运算后再“换回来”。 这正是 (BYTE*&)p 的核心目的:让 p 暂时表现得像 BYTE*,以便做字节偏移,然后自动变回原类型。 🔍 技术本质解析: 表达式 (T*&)x 的含义是: 将变量 x 的内存地址处的内容,重新解释为一个 T* 类型的左值引用(lvalue reference)。 这意味着: 如果 x 本身就是一个指针(比如 CNode* x),那么 (BYTE*&)x 就是一个 对 x 的引用,但视其类型为 BYTE*。 对这个引用赋值或做算术运算,会直接修改 x 的值(即指针地址),但按 BYTE* 的规则计算偏移。 这与以下代码等价: BYTE*& alias = reinterpret_cast<BYTE*&>(x); alias += offset; // 修改 alias 即修改 x 所以,从 C++ 标准角度看,这属于: 通过引用进行的 reinterpret_cast 风格的类型转换。 ⚠️ 注意:这不是“取地址再解引用” 有些人误以为 *& 是“先取地址再解引用”,比如: *&x // 等价于 x(恒等操作) 但这和 (Type*&)x 完全不同! *&x 是两个操作符:&x 取地址,* 解引用 → 结果还是 x。 (BYTE*&)x 是一个强制类型转换(cast),把 x 当作 BYTE*& 类型来处理。 ✅ 所以:*& 在这里不是操作符组合,而是类型名的一部分: BYTE* & → “BYTE 指针的引用” 写作 (BYTE*&) 只是为了省略空格,符合 C 风格宏/紧凑写法习惯。 📚 类似用法在经典代码中很常见 Windows SDK、MFC、COM 代码中大量使用 (BYTE*&), (DWORD*&), (void*&) 等。 目的几乎都是:对指针变量本身进行字节级偏移操作,同时避免临时变量。
有什么区别啊, 156,157 两行 154: CStringData *pData = (CStringData*)_afxAlloc64.Alloc(); 00E384C8 mov ecx,offset _afxAlloc64 (018cfdd0) 00E384CD call CFixedAlloc::Alloc (00433faa) 00E384D2 mov dword ptr [ebp-14h],eax 155: pData->nAllocLength = 64; 00E384D5 mov eax,dword ptr [ebp-14h] 00E384D8 mov dword ptr [eax+8],40h 156: void*& ptr = (void*&)pData; 00E384DF lea ecx,[ebp-14h] 00E384E2 mov dword ptr [ebp-18h],ecx 157: void* ptr2 = (void*)pData; 00E384E5 mov edx,dword ptr [ebp-14h] 00E384E8 mov dword ptr [ebp-1Ch],edx 156: void*& ptr = (void*&)pData; // 引用:ptr 是 pData 的别名 157: void* ptr2 = (void*)pData; // 拷贝:ptr2 是 pData 值的一个副本 ptr 是 pData 的“另一个名字”(别名),修改 ptr 就等于修改 pData; 而 ptr2 只是 pData 当前值的一个“快照”,修改 ptr2 不会影响 pData。 | 特性 | 第 156 行:`void*& ptr = (void*&)pData;` | 第 157 行:`void* ptr2 = (void*)pData;` | |------|----------------------------------------|----------------------------------------| | 类型 | `void*` 的 引用(reference) | `void*` 的 值(普通指针变量) | | 存储 | 不分配新内存,`ptr` 就是 `pData` 的别名 | 分配新变量(`ptr2`),拷贝 `pData` 的值 | | 修改影响 | `ptr = nullptr;` → `pData` 变为 `nullptr` | `ptr2 = nullptr;` → `pData` 不变 | | 汇编体现 | 取 `pData` 的地址(`lea`) | 取 `pData` 的值(`mov`) | -------------------------------------------------------------------------------- ❓为什么 MFC 要用 (void*&)pData? 在你的上下文中,这通常出现在 需要将 pData 传给一个接受 void*& 参数的函数,例如: void Free(void*&); Free((void*&)pData); // 函数内可将 pData 置为 nullptr 或者用于 统一内存管理接口,让分配器能直接修改传入的指针变量。
// CString _AFX_INLINE CStringData* CString::GetData() const { ASSERT(m_pchData != NULL); return ((CStringData*)m_pchData)-1; } _AFX_INLINE void CString::Init() { m_pchData = afxEmptyString.m_pchData; } #ifndef _AFXDLL _AFX_INLINE CString::CString() { m_pchData = afxEmptyString.m_pchData; } #endif _AFX_INLINE CString::CString(const unsigned char* lpsz) { Init(); *this = (LPCSTR)lpsz; } _AFX_INLINE int CString::GetLength() const { return GetData()->nDataLength; } _AFX_INLINE int CString::GetAllocLength() const { return GetData()->nAllocLength; } _AFX_INLINE BOOL CString::IsEmpty() const { return GetData()->nDataLength == 0; } _AFX_INLINE CString::operator LPCTSTR() const { return m_pchData; } _AFX_INLINE int PASCAL CString::SafeStrlen(LPCTSTR lpsz) { return (lpsz == NULL) ? 0 : lstrlen(lpsz); } void CString::AllocBuffer(int nLen) // always allocate one extra character for '\0' termination // assumes [optimistically] that data length will equal allocation length { ASSERT(nLen >= 0); ASSERT(nLen <= INT_MAX-1); // max size (enough room for 1 extra) if (nLen == 0) Init(); else { CStringData* pData; #ifndef _DEBUG if (nLen <= 64) { pData = (CStringData*)_afxAlloc64.Alloc(); pData->nAllocLength = 64; } else if (nLen <= 128) { pData = (CStringData*)_afxAlloc128.Alloc(); pData->nAllocLength = 128; } else if (nLen <= 256) { pData = (CStringData*)_afxAlloc256.Alloc(); pData->nAllocLength = 256; } else if (nLen <= 512) { pData = (CStringData*)_afxAlloc512.Alloc(); pData->nAllocLength = 512; } else #endif { pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)]; pData->nAllocLength = nLen; } pData->nRefs = 1; pData->data()[nLen] = '\0'; pData->nDataLength = nLen; m_pchData = pData->data(); } } void FASTCALL CString::FreeData(CStringData* pData) { #ifndef _DEBUG int nLen = pData->nAllocLength; if (nLen == 64) _afxAlloc64.Free(pData); else if (nLen == 128) _afxAlloc128.Free(pData); else if (nLen == 256) _afxAlloc256.Free(pData); else if (nLen == 512) _afxAlloc512.Free(pData); else { ASSERT(nLen > 512); delete[] (BYTE*)pData; } #else delete[] (BYTE*)pData; #endif } void CString::Release() { if (GetData() != _afxDataNil) { ASSERT(GetData()->nRefs != 0); if (InterlockedDecrement(&GetData()->nRefs) <= 0) FreeData(GetData()); Init(); } } void PASCAL CString::Release(CStringData* pData) { if (pData != _afxDataNil) { ASSERT(pData->nRefs != 0); if (InterlockedDecrement(&pData->nRefs) <= 0) FreeData(pData); } } void CString::Empty() { if (GetData()->nDataLength == 0) return; if (GetData()->nRefs >= 0) Release(); else *this = &afxChNil; ASSERT(GetData()->nDataLength == 0); ASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0); } void CString::CopyBeforeWrite() { if (GetData()->nRefs > 1) { CStringData* pData = GetData(); Release(); AllocBuffer(pData->nDataLength); memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR)); } ASSERT(GetData()->nRefs <= 1); } CString::CString(LPCTSTR lpsz) { Init(); if (lpsz != NULL && HIWORD(lpsz) == NULL) { UINT nID = LOWORD((DWORD)lpsz); if (!LoadString(nID)) TRACE1("Warning: implicit LoadString(%u) failed\n", nID); } else { int nLen = SafeStrlen(lpsz); if (nLen != 0) { AllocBuffer(nLen); memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR)); } } }
南来地,北往的,上班的,下岗的,走过路过不要错过!
======================个性签名=====================
之前认为Apple 的iOS 设计的要比 Android 稳定,我错了吗?
下载的许多客户端程序/游戏程序,经常会Crash,是程序写的不好(内存泄漏?刚启动也会吗?)还是iOS本身的不稳定!!!
如果在Android手机中可以简单联接到ddms,就可以查看系统log,很容易看到程序为什么出错,在iPhone中如何得知呢?试试Organizer吧,分析一下Device logs,也许有用.
浙公网安备 33010602011771号