The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: ragdog on July 11, 2010, 05:04:12 PM

Title: VirtualFree
Post by: ragdog on July 11, 2010, 05:04:12 PM
Hi


I create with VirtualAlloc Palce for the  pszText
and after working with the text use i VirtualFree
How i can test if the memory free?

invoke GetWindowTextLength, hWnd
        .if eax > 0       
            inc eax
            mov dwBufferSize, eax
            invoke  VirtualAlloc,0,eax,MEM_COMMIT,PAGE_EXECUTE_READWRITE
               push ebx
                mov pszText, eax
                lea ebx,[eax]
                invoke GetWindowText,hWnd,ebx, dwBufferSize
                .if eax

                    ; Working with text.............

                    invoke  VirtualFree,dwBufferSize,ebx,MEM_DECOMMIT 
                .endif

Title: Re: VirtualFree
Post by: dedndave on July 11, 2010, 05:06:12 PM
QuoteVirtualFree...
Return Value
If the function succeeds, the return value is nonzero.

If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.

that's the easy way   :P
Title: Re: VirtualFree
Post by: cork on July 11, 2010, 05:24:33 PM
The return value is in the EAX register, as others pointed out to me. You probably know that, but anyway... just in case.
Title: Re: VirtualFree
Post by: ragdog on July 11, 2010, 05:27:13 PM
Thanks for your post

Yes i have already read this

invoke  VirtualFree,dwBufferSize,ebx,MEM_DECOMMIT   
                     .if eax==0
                         ;True
                        .elseif eax!=0
                           ;False
                     .endif

How i can test it if this really free can i this see in Ollydbg?

Title: Re: VirtualFree
Post by: oex on July 11, 2010, 05:31:43 PM
You have that the wrong way round ragdog

invoke  VirtualFree,dwBufferSize,ebx,MEM_DECOMMIT   
                     .if eax!=0
                         ;True
                         ;The memory is free
                        .elseif eax==0
                         ;False
                         ;The memory is not free
                     .endif

Reading further:
MEM_DECOMMIT
0x4000 Decommits the specified region of committed pages. After the operation, the pages are in the reserved state.

The function does not fail if you attempt to decommit an uncommitted page. This means that you can decommit a range of pages without first determining the current commitment state.

I dont use the function myself but I would imagine this function would help you:
VirtualQuery
http://msdn.microsoft.com/en-us/library/aa366902(v=VS.85).aspx
Title: Re: VirtualFree
Post by: redskull on July 11, 2010, 05:40:20 PM
Quote from: ragdog on July 11, 2010, 05:27:13 PM
How i can test it if this really free can i this see in Ollydbg?

The 'memory map' window in Olly will show you what memory is alloacted to your process.  Monitor it before and after the call, and you should see it the range dissapear.  As far as testing to see if it's there programatically, you need to either walk the VAD tree yourself (non-trivial), or just try and access it to see if your program crashes (or, more likely, set up an exception handler to deal with the success).

-r
Title: Re: VirtualFree
Post by: dedndave on July 11, 2010, 05:41:39 PM
well - the only way i can think of testing it is free (besides the success of the Free call), is to see if it can be re-allocated   :P
that seems rather silly, because the OS may not allocate that block unless you request it allocates all available memory

note: after you free a block, you may still be able to read and write to that block without generating an exception
of course, that sounds like a good way to make bad things happen - lol


ahhh - redskull is on to something, there   :P
there must be an easy API function to use that returns memory blocks allocated to the current process
Title: Re: VirtualFree
Post by: redskull on July 11, 2010, 05:48:07 PM
Quote from: dedndave on July 11, 2010, 05:41:39 PM
note: after you free a block, you may still be able to read and write to that block without generating an exception

Thats interesting, dedndave. What conditions can cause this behavior?

-r
Title: Re: VirtualFree
Post by: dedndave on July 11, 2010, 05:50:09 PM
try it out   :bg
i tried it once, expecting to generate the old "c0000005" error, but the program kept on trucking - lol
Title: Re: VirtualFree
Post by: cork on July 11, 2010, 05:55:32 PM
Try IsBadReadPtr(). That might work, though I don't understand why the return value of VirtualFree() isn't sufficient.
Title: Re: VirtualFree
Post by: ragdog on July 11, 2010, 05:58:21 PM
Ok thanks  :U

This was my Mistake ::)
Title: Re: VirtualFree
Post by: dedndave on July 11, 2010, 07:21:56 PM
lol - let's call it microsoft's mistake, instead
one would naturally expect the exception error
Title: Re: VirtualFree
Post by: ragdog on July 18, 2010, 02:37:16 PM
I have trouble with this virtualfree

Why Free this not the memory

.data?
nSize  dd ?
pszMem dd ?

.code
push    hWnd
call    AllocateEditBuffer

.if (pszMem != NULL)
  invoke    MessageBox,0,addr pszMem,0,MB_OK
      call       DeAllocateMem
.endif

AllocateEditBuffer Proc uses ebx hWnd:HWND
   invoke    GetWindowTextLength, hWnd
   .if (eax>0)
        inc    eax
        mov    nSize, eax
     invoke VirtualAlloc,0,eax,MEM_COMMIT,PAGE_READWRITE
     .if (eax != NULL)
         mov pszMem,eax
          invoke    GetWindowText,hWnd,  pszMem,nSize
          .if (pszMem != NULL)

              ret
          .endif
     .endif
   .endif
   ret
AllocateEditBuffer endp

DeAllocateMem proc
               invoke VirtualFree,pszMem, nSize,MEM_DECOMMIT
               .if (eax!=0)
                   invoke    MessageBox,0,CTEXT ("The memory is free"),0,MB_OK
                 .else
                       invoke    MessageBox,0,CTEXT ("The memory is not free"),0,MB_OK
               .endif
ret
DeAllocateMem endp

Allocate the memory works fine only not this Free Mem (VirtualFree)
Title: Re: VirtualFree
Post by: redskull on July 18, 2010, 04:16:21 PM
MEM_DECOMMIT doesn't "free" the memory; it leaves the address space reserved to your program, but with no backing RAM (and/or pagefile space) behind it.  So, you must specificy how you define "failure" for this snippit (VirtualFree fails, memory still visible in Olly, can still read and write to it, etc).  By decomiting only, the addressess appear to be there, but don't actually exist.

-r
Title: Re: VirtualFree
Post by: ragdog on July 18, 2010, 04:33:30 PM
If i use MEM_DECOMMIT  or MEM_RELEASE have i ervery "The memory is not free" result

Title: Re: VirtualFree
Post by: asmfan on July 18, 2010, 05:15:27 PM
a hint: use MEM_COMMIT and MEM_RESERVE together, if MEM_RESERVE wasn't used previously. Then MEM_RELEASE will do its job fine.
Title: Re: VirtualFree
Post by: ragdog on July 18, 2010, 06:36:31 PM
Thanks I comming not further with it

I have change to

invoke VirtualAlloc,0,eax,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE
mov pszMem,eax
...
..

invoke VirtualFree, pszMem,nSize,MEM_RELEASE
    .if (eax!=0)
        invoke    MessageBox,0,CTEXT ("The memory is free"),0,MB_OK
     .else
          invoke    MessageBox,0,CTEXT ("The memory is not free"),0,MB_OK
    .endif

With same result :red

Can you post me an example?
Title: Re: VirtualFree
Post by: oex on July 18, 2010, 06:57:56 PM
Quote from: ragdog on July 18, 2010, 06:36:31 PM
invoke VirtualFree, pszMem,nSize,MEM_RELEASE

If you specify this value, dwSize must be 0 (zero)



invoke VirtualAlloc,0,8192,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE
mov pszMem,eax

invoke VirtualFree, pszMem,0,MEM_RELEASE

print str$(eax)
inkey

eax prints '1'
Title: Re: VirtualFree
Post by: ragdog on July 18, 2010, 07:50:16 PM
Thanks

Now have i found this bug i have no idea why and how i can solve it

If the pszMem filled from GetWindowText  cannot free it

invoke    GetWindowText,hWnd,addr pszMem,nSize

I have try bevore i use VirtualFree ,use RtlZeroMemory without good result

Title: Re: VirtualFree
Post by: oex on July 18, 2010, 08:40:00 PM
I dont use windows controls but surely this would work?


invoke VirtualAlloc,0,8192,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE
mov pszMem,eax

invoke GetWindowText,hWnd,pszMem,nSize <---- Note not 'ADDR pszMem'

invoke VirtualFree, pszMem,0,MEM_RELEASE

Where nSize is the number of characters you want to copy
Title: Re: VirtualFree
Post by: ragdog on July 18, 2010, 08:51:20 PM
Quote
invoke GetWindowText,hWnd,pszMem,nSize <---- Note not 'ADDR pszMem'

Without use addr works this VirtualFree

But I cannot get the text from edit control :wink


Gives a other way with other alloc apis?
Title: Re: VirtualFree
Post by: MichaelW on July 18, 2010, 10:17:19 PM
The functions all appear to work the way they are documented to work.

;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================
    .data
        pMem dd 0
    .code
;==============================================================================
ShowState proc ptrMem:DWORD
    LOCAL mbi:MEMORY_BASIC_INFORMATION
    invoke VirtualQuery, ptrMem, ADDR mbi, SIZEOF mbi
    SWITCH mbi.State
      CASE MEM_COMMIT
        print "MEM_COMMIT",13,10
      CASE MEM_FREE
        print "MEM_FREE",13,10
      CASE MEM_RESERVE
        print "MEM_RESERVE",13,10
    ENDSW
    ret
ShowState endp
;==============================================================================
start:
;==============================================================================
    invoke ShowState, pMem

    invoke VirtualAlloc, NULL, 1024, MEM_COMMIT, PAGE_READWRITE
    mov pMem, eax
    .IF eax == 0
        print LastError$(),13,10
    .ENDIF

    invoke ShowState, pMem

    invoke VirtualFree, pMem, 0, MEM_RELEASE
    .IF eax == 0
        print LastError$(),13,10
    .ENDIF

    invoke ShowState, pMem

    invoke VirtualAlloc, NULL, 1024, MEM_RESERVE, PAGE_READWRITE
    mov pMem, eax
    .IF eax == 0
        print LastError$(),13,10
    .ENDIF

    invoke ShowState, pMem

    invoke VirtualFree, pMem, 0, MEM_DECOMMIT
    .IF eax == 0
        print LastError$(),13,10
    .ENDIF

    invoke ShowState, pMem

    invoke VirtualFree, pMem, 0, MEM_RELEASE
    .IF eax == 0
        print LastError$(),13,10
    .ENDIF

    invoke ShowState, pMem

    inkey "Press any key to exit..."
    exit
;==============================================================================
end start

typedef struct _MEMORY_BASIC_INFORMATION {
  PVOID BaseAddress;
  PVOID AllocationBase;
  DWORD AllocationProtect;
  SIZE_T RegionSize;
  DWORD State;
  DWORD Protect;
  DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;


MEM_FREE
MEM_COMMIT
MEM_FREE
MEM_RESERVE
MEM_RESERVE
MEM_FREE


And the same for this code:

;==============================================================================
; Build as console app so print can display.
;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================

IDC_EDIT  equ 101
IDC_BTNU  equ 102
IDC_BTNL  equ 103

;==============================================================================
    .data
      hInstance     dd 0
      hwndEdit      dd 0
    .code
;==============================================================================

DlgProc proc hwndDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

    LOCAL pMem:DWORD, tLength:DWORD

    SWITCH uMsg

        CASE WM_INITDIALOG

            invoke GetDlgItem, hwndDlg, IDC_EDIT
            mov hwndEdit, eax

        CASE WM_COMMAND

            SWITCH wParam

                CASE IDC_BTNU

                    invoke GetWindowTextLength, hwndEdit
                    inc eax
                    mov tLength, eax
                    print str$(eax),13,10
                    invoke VirtualAlloc, NULL, eax, MEM_COMMIT, PAGE_READWRITE
                    mov pMem, eax
                    print hex$(eax),13,10
                    invoke GetWindowText, hwndEdit, pMem, tLength
                    print str$(eax),13,10
                    invoke crt__strupr, pMem
                    print hex$(eax),13,10
                    invoke SetWindowText, hwndEdit, pMem
                    print str$(eax),13,10
                    invoke VirtualFree, pMem, 0, MEM_RELEASE
                    print str$(eax),13,10,13,10


                CASE IDC_BTNL

                    invoke GetWindowTextLength, hwndEdit
                    inc eax
                    mov tLength, eax
                    print str$(eax),13,10
                    invoke VirtualAlloc, NULL, eax, MEM_COMMIT, PAGE_READWRITE
                    mov pMem, eax
                    print hex$(eax),13,10
                    invoke GetWindowText, hwndEdit, pMem, tLength
                    print str$(eax),13,10
                    invoke crt__strlwr, pMem
                    print hex$(eax),13,10
                    invoke SetWindowText, hwndEdit, pMem
                    print str$(eax),13,10
                    invoke VirtualFree, pMem, 0, MEM_RELEASE
                    print str$(eax),13,10,13,10

                CASE IDCANCEL

                    invoke EndDialog, hwndDlg, 0

            ENDSW

        CASE WM_CLOSE

            invoke EndDialog, hwndDlg, 0

    ENDSW

    xor   eax, eax
    ret

DlgProc endp

;==============================================================================
start:
;==============================================================================

    invoke GetModuleHandle, NULL
    mov   hInstance, eax

    Dialog "Test", \
           "MS Sans Serif",10, \
           WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           3,0,0,130,110,1024

    DlgEdit WS_BORDER or ES_MULTILINE or ES_WANTRETURN or \
            WS_VSCROLL or WS_HSCROLL or ES_AUTOVSCROLL or ES_AUTOHSCROLL, \
            7,7,113,65,IDC_EDIT

    DlgButton "UCASE",0,28,82,30,10,IDC_BTNU
    DlgButton "LCASE",0,68,82,30,10,IDC_BTNL

    CallModalDialog hInstance,0,DlgProc,NULL

    exit
;==============================================================================
end start

Title: Re: VirtualFree
Post by: ragdog on July 25, 2010, 09:19:37 AM
Hi

My problem is solved and works fine

Now have i a other question to allocate memory

I need for my project more allocate memory for use 2 buffers!

I know as one might call this function 2 times .
My thinking is a other way to not use 2 times this function


My steps:

invoke VirtualAlloc,NULL,1000...
.if (eax)
mov    pszMem,eax ;pszMem is now 1000 bytes reserved

mov pszMem2,eax ;[eax /2]

.endif

Now have i in pszMem2 500 bytes or?

And by VirtualFree
VirtualFree,pszMem,1000,MEM_DECOMMIT

Now is pszMem and pszMem2 free

Could this work?



Title: Re: VirtualFree
Post by: jj2007 on July 25, 2010, 01:29:54 PM
.if (eax)
mov    pszMem,eax ;pszMem is now 1000 bytes reserved
add eax, 500   ; NOW you have 2*500 bytes of buffer
mov pszMem2,eax ;[eax /2]

.endif
Title: Re: VirtualFree
Post by: ragdog on July 25, 2010, 02:43:47 PM
Thanks for your post

I hope i understand this correct ::)
mov pszMem,eax ;is the pointer to the allocated memory with 1000 bytes
add eax, 500      ;add to this pointer 500
mov pszMem2,eax

Then have i in pszMem 500 bytes and in pszMem2 500bytes?

Why say you  2*500 bytes of buffer?

Greets
Title: Re: VirtualFree
Post by: dedndave on July 25, 2010, 06:02:50 PM
2 x 500 = 1000

you are allocating 1000 bytes and splitting it into two 500-byte buffers

when you free the allocated block, you will only need to free the original 1000-byte block base address (handle)
Title: Re: VirtualFree
Post by: KeepingRealBusy on July 25, 2010, 06:05:56 PM
Quote from: oex on July 18, 2010, 06:57:56 PM
Quote from: ragdog on July 18, 2010, 06:36:31 PM
invoke VirtualFree, pszMem,nSize,MEM_RELEASE

If you specify this value, dwSize must be 0 (zero)



invoke VirtualAlloc,0,8192,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE
mov pszMem,eax

invoke VirtualFree, pszMem,0,MEM_RELEASE

print str$(eax)
inkey

eax prints '1'

This is what I always use. I allocate a huge hunk, then completely free it when I am done.

Dave.
Title: Re: VirtualFree
Post by: redskull on July 25, 2010, 07:09:48 PM
Just for the record, it's rather fruitless to reserve anything less than 64k of memory using VirtualAlloc; While windows will reserve things 4K at a time, it positions them on 64K aligned boundaries.  Consequently, reserving less than that essentially wastes all the other address space, which can never be used.  To be totally optimal, you should reserve 64K chunks of address space at a time, and then commit them 4K at a time, as needed.  If you have lots of smaller allocations, the heap is a more convienent option

-r
Title: Re: VirtualFree
Post by: KeepingRealBusy on July 26, 2010, 01:12:08 AM
Quote from: redskull on July 25, 2010, 07:09:48 PM
Just for the record, it's rather fruitless to reserve anything less than 64k of memory using VirtualAlloc; While windows will reserve things 4K at a time, it positions them on 64K aligned boundaries.  Consequently, reserving less than that essentially wastes all the other address space, which can never be used.  To be totally optimal, you should reserve 64K chunks of address space at a time, and then commit them 4K at a time, as needed.  If you have lots of smaller allocations, the heap is a more convienent option

-r

The following is a map of all of the memory I can allocate in one of my programs:


                                                Base        Size        End
Bases

0x004075C7  00 00 41 00                     ;   41000000    7c3f0000    BD3F0000
0x004075CB  00 00 b2 7c                     ;   7cb20000    02bd0000    7F6F0000
0x004075CF  00 00 7f 7f                     ;   7f7f0000    007bf000    7FFAF000
0x004075D3  00 00 32 00                     ;   00320000    000df000    3FF000
0x004075D7  00 00 00 00                     ;   
0x004075DB  00 00 00 00                     ;   
0x004075DF  00 00 00 00                     ;   
0x004075E3  00 00 00 00                     ;   
0x004075E7  00 00 00 00                     ;   
0x004075EB  00 00 00 00                     ;

                                                Size
Sizes

0x004075EF  00 00 3f 7c                     ;   7c3f0000
0x004075F3  00 00 bd 02                     ;   02bd0000
0x004075F7  00 f0 7b 00                     ;   007bf000
0x004075FB  00 f0 0d 00                     ;   000df000
0x004075FF  00 00 00 00                     ;   
0x00407603  00 00 00 00                     ;   


You will notice that the last 2 allocations are not mod 64K in size, in fact they are mod 4K. I allocate these by trying to get the biggest piece I can, then saving the base and size. Then I try again up to 9 more times, getting smaller and smaller pieces.

If I limited myself to 64K sized requests, I would not get the 30 4K blocks (f000 of 007bf000) and (f000 of 000df000).

To be sure, you need to temper this. I allocated all available memory then forced an error (load from location 0). The program terminated with no message. I then started allocating space between the first and subsequent allocations with a 4K block, and freed the special space after I got the last available block, then I tried the bad access. I grew this special block until Visual Studio could be brought in to report the error. I then hardcoded this special size. I now get the biggest piece, the special block, then the remaining space, then free the special block. No more problems.

Dave.
Title: Re: VirtualFree
Post by: redskull on July 26, 2010, 01:58:47 AM
The size of existing allocations is not related to the allocation granularity; it's the BASE that is configured to mod 64k.  For example, the allocation at 320000 is base 64K, and the 'end' is at 003FF000.  That means all the address space between 003FF001 and 040000 is now both inaccessible and unallocable.

-r
Title: Re: VirtualFree
Post by: KeepingRealBusy on July 26, 2010, 02:09:12 AM
I understand. What I am saying is that you forgo some amount (in my case 30 4K blocks) of memory you could allocate (and then dispense in 4K blocks) if you only ask for blocks of 64K. The system could not give me the extra 4K at the end of that allocation because something was loaded there.

Dave.