【问题标题】:Unhandled exception at 0x61e1f5cf (msvcr90d.dll) in start.exe: 0xC0000005: Access violation writing location 0x00000000start.exe 中 0x61e1f5cf (msvcr90d.dll) 处的未处理异常:0xC0000005:访问冲突写入位置 0x00000000
【发布时间】:2012-01-05 01:44:38
【问题描述】:

包括“stdafx.h”

#include<stdio.h>
#include<string.h>
#define MAX_ET_TABLES 10

typedef struct{
    unsigned char  ucVersion;
    unsigned char enMonitor;
    unsigned short uPid;
}SData_t;
typedef struct{
    unsigned char ucVersion;
    unsigned short uID;
    unsigned int uiCollected;
    SData_t st[MAX_ET_TABLES];
}STData_t; 

typedef struct{
   STData_t stData;   
}psTask;

psTask *pstTask;

int main()
{
    printf("\npstTask->stData = %u\n",&pstTask->stData);
    memset(&(pstTask->stData), 0xFF, sizeof(pstTask->stData)); 
    return 0;
}

我需要将结构变量的值设置为 0xFF。

上面的程序抛出一个未处理的异常为“Unhandled exception at start.exe 中的 0x61e1f5cf (msvcr90d.dll):0xC0000005:访问冲突写入位置 0x00000000。”请帮助我理解为什么会这样。

      page    ,132
        title   memset - set sections of memory all to one byte
;***
;memset.asm - set a section of memory to all one byte
;
;       Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
;       contains the memset() routine
;
;*******************************************************************************

        .xlist
        include cruntime.inc
        .list

page
;***
;char *memset(dst, value, count) - sets "count" bytes at "dst" to "value"
;
;Purpose:
;       Sets the first "count" bytes of the memory starting
;       at "dst" to the character value "value".
;
;       Algorithm:
;       char *
;       memset (dst, value, count)
;               char *dst;
;               char value;
;               unsigned int count;
;               {
;               char *start = dst;
;
;               while (count--)
;                       *dst++ = value;
;               return(start);
;               }
;
;Entry:
;       char *dst - pointer to memory to fill with value
;       char value - value to put in dst bytes
;       int count - number of bytes of dst to fill
;
;Exit:
;       returns dst, with filled bytes
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

        CODESEG

    extrn   _VEC_memzero:near
    extrn   __sse2_available:dword

        public  memset
memset proc \
        dst:ptr byte, \
        value:byte, \
        count:dword

        OPTION PROLOGUE:NONE, EPILOGUE:NONE

        .FPO    ( 0, 3, 0, 0, 0, 0 )

        mov     edx,[esp + 0ch] ; edx = "count"
        mov     ecx,[esp + 4]   ; ecx points to "dst"

        test    edx,edx         ; 0?
        jz      short toend     ; if so, nothing to do

        xor     eax,eax
        mov     al,[esp + 8]    ; the byte "value" to be stored

; Special case large block zeroing using SSE2 support
    test    al,al ; memset using zero initializer?
    jne     dword_align
    cmp     edx,0100h ; block size exceeds size threshold?
    jb      dword_align
    cmp     DWORD PTR __sse2_available,0 ; SSE2 supported?
    je      dword_align

    jmp     _VEC_memzero ; use fast zero SSE2 implementation
    ; no return

; Align address on dword boundary
dword_align:

        push    edi             ; preserve edi
        mov     edi,ecx         ; edi = dest pointer

        cmp     edx,4           ; if it's less then 4 bytes
        jb      tail            ; tail needs edi and edx to be initialized

        neg     ecx
        and     ecx,3           ; ecx = # bytes before dword boundary
        jz      short dwords    ; jump if address already aligned

        sub     edx,ecx         ; edx = adjusted count (for later)
adjust_loop:
        mov     [edi],al
        add     edi,1
        sub     ecx,1
        jnz     adjust_loop

dwords:
; set all 4 bytes of eax to [value]
        mov     ecx,eax         ; ecx=0/0/0/value
        shl     eax,8           ; eax=0/0/value/0

        add     eax,ecx         ; eax=0/0val/val

        mov     ecx,eax         ; ecx=0/0/val/val

        shl     eax,10h         ; eax=val/val/0/0

        add     eax,ecx         ; eax = all 4 bytes = [value]

; Set dword-sized blocks
        mov     ecx,edx         ; move original count to ecx
        and     edx,3           ; prepare in edx byte count (for tail loop)
        shr     ecx,2           ; adjust ecx to be dword count
        jz      tail            ; jump if it was less then 4 bytes

>         rep     stosd         // the arrow comes here when that exception is thrown

main_loop_tail:
        test    edx,edx         ; if there is no tail bytes,
        jz      finish          ; we finish, and it's time to leave
; Set remaining bytes

tail:
        mov     [edi],al        ; set remaining bytes
        add     edi,1

        sub     edx,1           ; if there is some more bytes
        jnz     tail            ; continue to fill them

; Done
finish:
        mov     eax,[esp + 8]   ; return dest pointer
        pop     edi             ; restore edi

        ret

toend:
        mov     eax,[esp + 4]   ; return dest pointer

        ret

memset  endp

        end

已编辑:

int main()
{
    psTask *pstTask;
    pstTask = (psTask*)malloc(sizeof(psTask));
    pstTask = NULL;
    printf("\npstTask->stData = %u\n",&pstTask->stData);
    memset(&(pstTask->stData), 0xFF, sizeof(pstTask->stData)); 
    return 0;
}

我试过这样,但仍然出现异常。请帮助。

【问题讨论】:

    标签: c


    【解决方案1】:

    由于pstTask 是一个全局变量,这一行:

    psTask *pstTask;
    

    等价于:

    psTask *pstTask = 0x00000000;
    

    并且由于您以后再也不会将其更改为指向其他任何地方(例如,正确分配的内存),因此这一行:

        memset(&(pstTask->stData), 0xFF, sizeof(pstTask->stData));
    

    等价于:

        memset(0x00000000, 0xFF, sizeof(pstTask->stData));
    

    (因为stDatapsTask 结构的第一个元素,所以偏移量为零)。这意味着您正在尝试将 0xFF 写入内存位置 0x00000000(以及随后的 47 个字节左右),而不是写入您实际有权写入的内存(例如堆栈空间或返回的空间malloc)。


    更新更新问题:

    这一点:

        pstTask = (psTask*)malloc(sizeof(psTask));
        pstTask = NULL;
    

    psTask 分配内存并将pstTask 指向它——到目前为止一切都很好——但随后它将pstTask 设置回NULL(即,没有指向任何有效的地方)。您需要删除第二行。

    此外,在调用malloc 之后,您应该始终检查它的返回值;如果它返回NULL,则表示您的内存不足。所以,你应该这样写:

        pstTask = (psTask*)malloc(sizeof(psTask));
        if(pstTask == NULL)
        {
            fprintf(stderr, "Out of memory.\n");
            return 1;
        }
        printf("\npstTask->stData = %u\n",&pstTask->stData);
    

    (在这种特定情况下,我确信malloc 将成功返回分配的内存,但您真的应该始终检查它的返回值。)

    【讨论】:

    • @ruakh :谢谢你清楚地解释我。我已经做了一些修改,但我仍然得到了异常老兄。
    • 第一个等式通常是正确的,只是因为0x00000000 是一个空指针常量。它在pstTask 中存储了一个空指针值,该值并非必要 全部为零(尽管碰巧它是在Windows 上,这显然是程序运行的环境)。我发现用空指针而不是0x00000000 来考虑它更清楚。
    • @KeithThompson:嗯,是的。我选择 0x00000000 作为我的空指针表示法,因为这就是 OP 的错误消息中的内容。我想我应该在答案的某处明确使用短语“空指针”,但这似乎并不重要,因为问题实际上是pstTask 没有指向任何地方,而不是明确指出它是空的。 (如果您要抱怨空指针必须全为零的潜在错误暗示,那么为什么不抱怨指针必须为 32 位长的潜在错误暗示呢?)
    • @Angus:在您上次发表评论大约一小时后,您接受了我的回答。这是否意味着您发现了问题,或者您仍然需要帮助? (在后一种情况下,您应该不接受我的回答,因为现在人们会认为您不再需要帮助。)
    • @ruakh:谢谢你帮助我理解老兄。谢谢。我会试试的,让你知道。
    猜你喜欢
    • 2013-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 2013-01-23
    • 2012-11-03
    相关资源
    最近更新 更多