C++ 在缓冲区溢出时自动截断和null终止字符串缓冲区
我有以下代码,可以从指定父窗口的所有子窗口加载文本。它运行良好,但有时,有一些父窗口(例如打开了记事本,使用了很长的C++源文件),这些文件有大量的文本并导致缓冲区溢出。C++ 在缓冲区溢出时自动截断和null终止字符串缓冲区,c++,winapi,truncate,buffer-overflow,C++,Winapi,Truncate,Buffer Overflow,我有以下代码,可以从指定父窗口的所有子窗口加载文本。它运行良好,但有时,有一些父窗口(例如打开了记事本,使用了很长的C++源文件),这些文件有大量的文本并导致缓冲区溢出。 BOOL CALLBACK EnumChildProc(__in HWND hWnd, __in LPARAM lParam) { LRESULT TEXT_LENGTH = NULL; WCHAR szText[32767]; LPWSTR szWindowText; UINT nBuffe
BOOL CALLBACK EnumChildProc(__in HWND hWnd, __in LPARAM lParam) {
LRESULT TEXT_LENGTH = NULL;
WCHAR szText[32767];
LPWSTR szWindowText;
UINT nBuffer = NULL, nText = NULL;
szWindowText = reinterpret_cast<LPWSTR>(lParam); szText[0] = L'\0';
nBuffer = (UINT)wcslen(szWindowText);
TEXT_LENGTH = SendMessage(hWnd, WM_GETTEXTLENGTH, NULL, NULL);
if (TEXT_LENGTH > NULL)
{
SendMessage(hWnd, WM_GETTEXT, (WPARAM)32767, reinterpret_cast<LPARAM>(&szText));
szText[TEXT_LENGTH] = L'\n'; szText[TEXT_LENGTH + 1] = L'\0';
while ((nBuffer < 32766) && (szText[nText] != L'\0'))
{ szWindowText[nBuffer++] = szText[nText++]; }
szWindowText[nBuffer] = L'\0';
}
return TRUE;
}
BOOL回调EnumChildProc(\uuu在HWND-HWND中,\uu在LPARAM中){
LRESULT TEXT_LENGTH=NULL;
WCHAR szText[32767];
LPWSTR文本;
UINT nBuffer=NULL,nText=NULL;
szWindowText=reinterpret_cast(LPRAM);szText[0]=L'\0';
nBuffer=(UINT)wcslen(szWindowText);
TEXT_LENGTH=SendMessage(hWnd,WM_GETTEXTLENGTH,NULL,NULL);
如果(文本长度>NULL)
{
SendMessage(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText));
szText[TEXT_LENGTH]=L'\n';szText[TEXT_LENGTH+1]=L'\0';
而((nBuffer<32766)和&(szText[nText]!=L'\0'))
{szWindowText[nBuffer++]=szText[nText++];}
szWindowText[nBuffer]=L'\0';
}
返回TRUE;
}
行SendMessage(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText))代码>有时会导致缓冲区溢出和我的应用程序崩溃
我知道如何检测这种溢出,比如if(TEXT_LENGTH>32767)
,但我无法动态增加缓冲区的大小szText
正如问题标题所提到的,我不想增加其大小,我只想将返回文本截断并空终止为最大缓冲区大小32767
(如果text\u LENGTH
超过32767
),并将其分配给szWindowText
,以用于其他目的
非常感谢您的帮助。有几件事:
最好将缓冲区动态分配到文本长度。(“\0”的+1)
在WM_GETTEXT中删除szText的&运算符,您只需要包含的地址,而不是指针的地址
当您显式使用字符时,请使用SendMessageA,否则VisualStudio将默认使用带有SendMessageW的wchar\u t。SendMessage是一个宏,可根据项目设置扩展为wchar\u t或char。或者将TCHAR类型与SendMessage一起使用,也可以将其扩展为正确的类型
DWORD l=SendMessage(hWnd,WM_GETTEXTLENGTH,NULL,NULL);
如果(l>0){
TCHAR*szText=新的TCHAR[l+1];
SendMessage(hWnd,WM_GETTEXT,(WPARAM)l+1,reinterpret_cast(szText));
//使用szText
删除文本;
}
基本上,您需要为\n
腾出空间,无论插入什么,方法是在WM\u GETTEXT
调用中使用szText-1的sizeof
而不是32767
注意:如果您必须使用Simonyi符号,请不要在不适用的地方使用它。关于szText
,没有以null结尾的内容,您仅将其用于WM_GETTEXT
发送消息(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText))代码>不应导致缓冲区溢出,因为提供了正确大小的缓冲区。实际上,根本不需要这个临时缓冲区
真正的问题是,在不知道目标缓冲区大小的情况下,将字符追加到作为lParam
提供的指针中。您应该提供目标缓冲区大小。不要将整数与NULL
进行比较,也不要初始化整数NULL
应该是空指针。即使定义为0
使用NULL
在语义上也是错误的,并且会误导阅读您代码的人。WCHAR szText[32767]
!!!知道长度后,为什么不使用std::wstring并动态调整其大小?SendMessage(hWnd,WM_GETTEXT,(WPARAM)32767,reinterpret_cast(&szText))代码>不应导致缓冲区溢出,因为提供了正确大小的缓冲区。实际上,根本不需要这个临时缓冲区。您真正的问题是,您正在写入作为lParam
提供的指针,而不知道目标缓冲区的大小。@VTT是的,您可以使用&some\u string\u object[0]
获取指向字符串中第一个元素的指针(一旦大小正确调整)。@Blueeyes789我不知道。那么呢?这个答案确实会影响OP提到的缓冲区溢出问题。它还建议做错误的事情:使用chars或TCHAR,而不是显式使用宽chars和W版本的函数。并且发布的代码片段包含错误:WPARAM
到SendMessage
应该包含目标缓冲区容量,即应该是l+1
,并且还应该检查第二次SendMessage
调用返回的值,以确定实际复制到缓冲区的字符数(虽然不太可能与l
)不同。好的,修复了缓冲区容量问题。但是,我不同意“使用宽字符和W版本”的观点。在我看来,您应该始终使用TCHAR、LPTSTR等以及win32 API函数的宏版本(因此不是“W”或“A”)因此,程序将适应项目设置中配置的任何内容
DWORD l = SendMessage(hWnd, WM_GETTEXTLENGTH, NULL, NULL);
if (l > 0){
TCHAR *szText = new TCHAR[l + 1];
SendMessage(hWnd, WM_GETTEXT, (WPARAM)l + 1, reinterpret_cast<LPARAM>(szText));
// use szText
delete[] szText;
}