测试OPCServer内存泄漏虚惊一场

      十年前用C++玩会opc client后就一直想玩server,但因工作原因一直没有使用的机会和紧迫感,也因为其难度,就一直搁置着。年后因为新的工作原因,必须搞会opc server。自知年纪大了,从头啃COM技术几乎是不可能,使用网上现成的dll又担心不稳定或是出问题后不知如何查故障。后从老毛子网站得到了lightopc的源码,便花了半个月啃下了这个,虽然已经是15年前的技术,但依然光彩闪耀。

      刚给客户移交了个opcserver,突然忘了测试是否内存泄漏情况,赶紧重测一遍。糟糕,加载变量时每个变量都报一次“Access in invalid memory: Attempt to access 1 byte(s) at 0x00000000.”追踪到是

      mbstowcs(0x00000000, 0x03E1FD3C ["HTDOPC.bianliang01"], 0x13 [19]) 

      这可如何是好,赶紧定位到 loAddRealTag,实现函数在dll中,还好有源码。一步步找到 mbstowcs,原来是以下一段代码:

typedef WCHAR   loWchar;
static void *trm[8000];
static unsigned tra;
#define SIZEOF_ARRAY(x) (sizeof(x)/sizeof(x[0]))
long mallocX_count = -1;
void TRAP_ALLOC(void *buf)
{
    if(tra < SIZEOF_ARRAY(trm))
    {
        //UL_TRACE((LOGID, "TRA: %u", tra));
        trm[tra++] = buf;
    }
    else
    {
        //UL_ERROR((LOGID, "mallocX TRAP OVERFLOW (%p)", buf));
    }
    mallocX_count++;
}
int lo_mbstowcs(loWchar *wcs, const char *mbs, int nn)
{
    int ii;
    // if (-1 == nn) nn = strlen(mbs);
#ifdef _WIN32
# if 0/* This is not quite right call but in this file 'len' is already counted */
    ii = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbs, nn, wcs, nn);
# else
    ii = mbstowcs(wcs, mbs, nn);//wcs 参数为0即报内存故障
# endif
    if(wcs && ii <= 0)
#endif
        for(ii = 0; ii < nn; ii++)
        {
#if 0
            wcs[ii] = (unsigned char)mbs[ii];
#else
            ((char *)wcs)[ii << 1] = mbs[ii];
            ((char *)wcs)[ii << 1 | 1] = '\0';
#endif
            if(!mbs[ii]) break;
        }
    /* if (wcs && ii < len) wcs[ii] = 0;*/
    return ii;
}
void *mallocX(unsigned size)
{
    unsigned *buf;
    // mallocX_trap();
    size += 4 * sizeof(unsigned) - 1;
    size /= sizeof(unsigned);
    buf = new unsigned[size];
    if(!buf) return 0;
    *buf++ = (size - 1) * sizeof(unsigned);
    TRAP_ALLOC(buf);
    return (void *)buf;
}
loWchar *loMWstrdup(const char *str)
{
    loWchar *ns;
    unsigned len;
    if(!str) return 0;
    len = strlen(str) + 1;
    len = lo_mbstowcs(0, str, len); /* lo_mbstowcs() never returns -1 */ //追踪到这里报不正常,第一个参数是0
    ns = (loWchar *)mallocX((len + 1) * sizeof(loWchar));
    if(ns)
    {
        lo_mbstowcs(ns, str, len);
        ns[len] = 0;
    }
    return ns;
}

为了便于重新调试,以上代码是节选。

测试代码:

      char x[24]="abcd0123";
      WCHAR *Y=loMWstrdup(x));

不开启内存检测时,执行正常,已开启内存检测就定位到了

ii = mbstowcs(wcs, mbs, nn);//wcs 参数为0即报内存故障

查了下 mbstowcs原型,size_t mbstowcs(wchar_t *dest, const char *src, size_t n);

特意注明了:

如dest 非NULL,则mbstowcs() 函数把多字符src转换成宽字符dest,最多转换到n个宽字符(即wchar_t);

如dest为NULL,则忽略参数n,转换仍然继续,只是不写到dest,最终返回转换成功的宽字符个数(不包括终止符'\0')

原作者真巧妙,第一次获取需要的内存大小,第二次再转换,还特意注明 

never returns -1

学艺不精,虚惊一场!


你可能感兴趣的:(bcb,C++,OPC)