XSLT存档  

不及格的程序员-八神

 查看分类:  ASP.NET XML/XSLT JavaScripT   我的MSN空间Blog

image

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,后面的数据是上一个日期框的数据残留

image

 

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*&) 等。
目的几乎都是:对指针变量本身进行字节级偏移操作,同时避免临时变量。

 

有什么区别啊,  156157 两行

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));
        }
    }
}

 

posted on 2026-04-02 10:24  不及格的程序员-八神  阅读(4)  评论(0)    收藏  举报