vb在调用API的一个Bug可能导致内存泄露,该怎么解决
vb在调用API的一个Bug可能导致内存泄露
其实这个问题我很早很早以前就发现了,只是一直没留意,也不在意。今天无意中又用VB写了一个程序全部使用NTDLL导出函数编写,又出现了这样的情况,这样就由不得我不注意了,经过我的反复测试以及反汇编验证,证实了vb6_sp6在调用某些API(测试的应该有很多API存在这样的问题)存在内存泄露问题或者是函数调用失败。请大家先看我写的简单两段代码。
代码一:
Option Explicit
Private Const MEM_RELEASE = &H8000
Private Const MEM_COMMIT = &H1000
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Sub Code1()
Dim Base As Long
Base = VirtualAlloc(ByVal 0&, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
If Base Then
MsgBox Hex(Base)
MsgBox VirtualFree(ByVal Base, 0, MEM_RELEASE)
MsgBox Hex(GetLastError)
End If
End Sub
这段代码是申请一段内存,然后马上释放它,代码没什么难以理解的非常简单。大家仔细看代码上好像也不存在有什么问题,那么问题在什么地方呢?
我一句一句来解析首先“Base = VirtualAlloc(ByVal 0&, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE)”
这行代码申请了一段长100字节的内存跟踪结果成功申请了得出某地址,然后我用msgbox把地址显示出来
这时这段地址是可用的,大家可以使用一些内存察看编辑工具,比如冰刃之类的。然后调用“VirtualFree ByVal Base, 0, MEM_RELEASE"释放内存,失败了。我检查了很久参数和API声明均没发现有什么问题那么问题出在什么地方呢?为了求证我写了代码二,也就是代码一最终在Ring3层调用的API函数
代码二:
Option Explicit
Private Const MEM_RELEASE = &H8000
Private Const MEM_COMMIT = &H1000
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Sub Code2()
Dim ntStatus As Long
Dim AllocationSize As Long
Dim ReturnLength As Long
Dim Base As Long
AllocationSize = 100
ntStatus = ZwAllocateVirtualMemory(-1, _
Base, _
0, _
AllocationSize, _
MEM_COMMIT, _
PAGE_EXECUTE_READWRITE _
)
If ntStatus >= 0 And Base Then
MsgBox Hex(Base)
AllocationSize = 0
ntStatus = ZwFreeVirtualMemory(-1, Base, AllocationSize, MEM_RELEASE)
MsgBox Hex(ntStatus)
End If
End Sub
同样出错在ZwFreeVirtualMemory这句上,这时函数有返回值,值为&HC00000F2查阅相关定义为
STATUS_INVALID_PARAMETER_4,说明第四个参数存在问题。这句话可就那纳闷了,好在前段时间在64位编程时也遇到这样的问题后来经过跟踪分析知道是传进去的数据按32位传进去的前面位补了FFFFFFFF所以出了错。我就猜测估计这里也是这样的问题然后我通过windbg进行双机调试断点下在nt!NtFreeVirtualMemory上发现了确实在第四个参数上进行了检测而这时我们传进去的值和我们本来想传进去的值有出入
------解决方案--------------------
本来 long (32bit) 就需要 写成 &HFF00&
某些API其实是 short (16bit) integer( -32768 ~ 32767 (因为是 16位操作系统中留下来的API)
你输入37268 > 32767 超出其范围,溢出了.
http://forums.techguy.org/software-development/495522-vb6-h-constants.html&HFF00 is hex FF00 a short (16bit) integer
&HFF00& is hex 0000FF00 a long (32bit) integer
&HFF0000 is hex 00FF0000 a long (32bit) integer
65536 is hex 00010000 is a long (32bit) remember the max value for a short integer is 65535 or (FFFF).
例子:
其实这个问题我很早很早以前就发现了,只是一直没留意,也不在意。今天无意中又用VB写了一个程序全部使用NTDLL导出函数编写,又出现了这样的情况,这样就由不得我不注意了,经过我的反复测试以及反汇编验证,证实了vb6_sp6在调用某些API(测试的应该有很多API存在这样的问题)存在内存泄露问题或者是函数调用失败。请大家先看我写的简单两段代码。
代码一:
Option Explicit
Private Const MEM_RELEASE = &H8000
Private Const MEM_COMMIT = &H1000
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Sub Code1()
Dim Base As Long
Base = VirtualAlloc(ByVal 0&, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
If Base Then
MsgBox Hex(Base)
MsgBox VirtualFree(ByVal Base, 0, MEM_RELEASE)
MsgBox Hex(GetLastError)
End If
End Sub
这段代码是申请一段内存,然后马上释放它,代码没什么难以理解的非常简单。大家仔细看代码上好像也不存在有什么问题,那么问题在什么地方呢?
我一句一句来解析首先“Base = VirtualAlloc(ByVal 0&, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE)”
这行代码申请了一段长100字节的内存跟踪结果成功申请了得出某地址,然后我用msgbox把地址显示出来
这时这段地址是可用的,大家可以使用一些内存察看编辑工具,比如冰刃之类的。然后调用“VirtualFree ByVal Base, 0, MEM_RELEASE"释放内存,失败了。我检查了很久参数和API声明均没发现有什么问题那么问题出在什么地方呢?为了求证我写了代码二,也就是代码一最终在Ring3层调用的API函数
代码二:
Option Explicit
Private Const MEM_RELEASE = &H8000
Private Const MEM_COMMIT = &H1000
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Function VirtualAlloc Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Sub Code2()
Dim ntStatus As Long
Dim AllocationSize As Long
Dim ReturnLength As Long
Dim Base As Long
AllocationSize = 100
ntStatus = ZwAllocateVirtualMemory(-1, _
Base, _
0, _
AllocationSize, _
MEM_COMMIT, _
PAGE_EXECUTE_READWRITE _
)
If ntStatus >= 0 And Base Then
MsgBox Hex(Base)
AllocationSize = 0
ntStatus = ZwFreeVirtualMemory(-1, Base, AllocationSize, MEM_RELEASE)
MsgBox Hex(ntStatus)
End If
End Sub
同样出错在ZwFreeVirtualMemory这句上,这时函数有返回值,值为&HC00000F2查阅相关定义为
STATUS_INVALID_PARAMETER_4,说明第四个参数存在问题。这句话可就那纳闷了,好在前段时间在64位编程时也遇到这样的问题后来经过跟踪分析知道是传进去的数据按32位传进去的前面位补了FFFFFFFF所以出了错。我就猜测估计这里也是这样的问题然后我通过windbg进行双机调试断点下在nt!NtFreeVirtualMemory上发现了确实在第四个参数上进行了检测而这时我们传进去的值和我们本来想传进去的值有出入
------解决方案--------------------
本来 long (32bit) 就需要 写成 &HFF00&
某些API其实是 short (16bit) integer( -32768 ~ 32767 (因为是 16位操作系统中留下来的API)
你输入37268 > 32767 超出其范围,溢出了.
http://forums.techguy.org/software-development/495522-vb6-h-constants.html&HFF00 is hex FF00 a short (16bit) integer
&HFF00& is hex 0000FF00 a long (32bit) integer
&HFF0000 is hex 00FF0000 a long (32bit) integer
65536 is hex 00010000 is a long (32bit) remember the max value for a short integer is 65535 or (FFFF).
例子:
- VB code
Option Explicit Private Const i = 32768 Private Const j = &H8000 '<--这里其实是 -32768 为什么呢? 因为是short (16bit) integer Private Const m = 32768 Private Const n = &H8000& '<--这个才是32768,因为是long (32bit) integer Private Sub Command1_Click() If i = j Then MsgBox ("True") '不会经过这里的. End If If m = n Then MsgBox ("True") End If End Sub