WCHAR overflow when performing wcscpy_s - c++

When trying to retrieve a massive folder path from an outlook mailbox (no 255 char max length in path) I seem not be be handling it correctly, yet i have tried everything on the code and nothing seems to shine some light on the issue.
Path: \\Mailbox - long\Inbox\fgsegesgrgesrgegthtrhrthyerytyertytthgfhgdfhdfh\sfhsjkdfhsjkhfweuifhskjefhjksdhjsdhfusehfklahdfajkehwfuasdf\sadfhjaehjfhaeufhuaseh9oa3heufhshudhjksahdfjkshadmldhasnf\awefuyawefioaw3yfiuapgpapwqq0uwqfeiusdfsgpsadncabpaw\iawehfiowaeghuiaegfwuioaghpaweufrhasdfhlkasvjdhlaehfuawieghgawgwaef\fasbclajsbvbwaubhvwabveuabvdjklzbdvjkhzusefhzlhsdf\vshiuwhpqphdfhvjsamhashmasdfvhnakjdsfiawjeijfvsadkjfsa\aefrghjksadfhjklshareuhsadhsahvsandvnlsdffalsdfh384fhsduafhl\fasfdlashjklefrhuaehfskhaahsdfhuhaiyeifoa38fodasfhsahdfklkkasdf\jkfhsakdfjhsjkladfhdsjkahfjkajkflashdfjkshafjksahfsdjafhsdjahfjsahldfkasf\fauiwehfeawhfjkhsakjfhsjkaefheuifhjksdhjkafhjksadhfjhaseuhfasjhdjkfhasfjhaskjdfhslaf\jklshadjkfhasjkhfjkaheuyhruiyq3y83yuryvnzxcvxzcviouxzcvzxvklzxvkl
Path Length: 766 to 812 char
Hopefully explaining it a bit better, the code;
if(....)
{
size_t n = wcslen(outlookFolderPath->Value.lpszW);
if(n < 100)
wcscpy_s(m_szInheritedFolderPath, outlookFolderPath->Value.lpszW);
else
{
WCHAR szTemp[2048] = {}, szText[2048]= {};
LoadStringW(ghInstDLL, IDS_PATH_TRUNCATED, szText, 2048);
swprintf_s(szTemp, szText, outlookFolderPath->Value.lpszW + ((n-80) * sizeof(WCHAR)));
wcscpy_s(m_szInheritedFolderPath, szTemp); // *** Dies Here ***
}
}
...
The fatal error occurrs at string.h line;
__DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_1(errno_t, wcscpy_s, wchar_t, _Dest, _In_z_ const wchar_t *, _Source)

(n-80) * sizeof(WCHAR).
That copies 160 characters in an array that's 100 characters long. Kaboom.
You want to count characters, not bytes. Delete * sizeof(WCHAR). And you ought to check for a surrogate.

swprintf_s(szTemp, szText, outlookFolderPath->Value.lpszW + ((n-80) * sizeof(WCHAR)));
Here the second argument is supposed to be the size of the buffer.

Related

What causes the heap corruption in my method?

So I have tracked down an annoying heap corruption to a single method.
DWORD gdwCounter = 0;
TCHAR* GetName(const TCHAR* format, size_t len)
{
len += (snprintf(NULL, 0, "%lu", gdwCounter) * sizeof(TCHAR));
TCHAR *c = (TCHAR*)malloc(len);
_stprintf_s(c, len, __TEXT("%s%lu"), format, gdwCounter);
return c;
}
To make sure I found the correct method, I tried to change it and just copy the 'format' buffer it gets passed as an parameter to the output buffer. Heap corruption went away and everything was fine again.
I decided to look at the documentations of snprintf and _stprintf_s.
snprintf is supposed to return the required characters without the null-terminating character to actually print your buffer in a second call to it.
My len parameter already contains the full size (with null-terminating character) of format.
Also I couldn't find any hints to what is wrong in the documentation of _stprintf_s.
So what am I missing?
Edit: After further testing I found out that apparently _stprintf_s causes the error as snprintf does return the correct size.
TCHAR* GetName(const TCHAR* format, size_t len)
{
len += snprintf(NULL, 0, "%lu", gdwCounter);
TCHAR *c = (TCHAR*)malloc(len*sizeof(TCHAR));
_stprintf_s(c, len, __TEXT("%s%lu"), format, gdwCounter);
return c;
}
_stprintf_s takes the "Maximum number of characters to store" instead of maximum number of bytes.

wchar_t array size issue with wcscpy_s

I'm confused with a size issue. Running the following code throws an exception at runtime. Specifically it seems to appear at end, and the text still be pasted with success. Due to my limited skills I'm not able to interpret the exception clearly.
It started when I decided to use the wcscpy_s function due to depreciation of wcscpy which worked fine in my noob program.
#define _CRT_SECURE_NO_WARNINGS
#include <afxwin.h>
int main() {
wchar_t wcSource[7] = L"Testeu"; // Throws an exception error. However, wcSource[8] doesn't
//wchar_t wcSource[9] = L"TestCopy"; // Runs fine
UINT iSize = sizeof(wcSource);
if (OpenClipboard(NULL)) {
EmptyClipboard();
HGLOBAL hClipboardData;
hClipboardData = GlobalAlloc(GMEM_DDESHARE, iSize);
wchar_t *wpchData;
wpchData = (wchar_t*)GlobalLock(hClipboardData);
//wcscpy(wpchData, wcSource); // Works fine
wcscpy_s(wpchData, iSize, wcSource);
GlobalUnlock(hClipboardData);
SetClipboardData(CF_UNICODETEXT, hClipboardData);
CloseClipboard();
}
return 0;
}
wcscpy_s() expects a CHARACTER count, but you are passing it a BYTE count instead. On Windows, sizeof(wchar_t) is 2 bytes.
You need a BYTE count when allocating memory for the clipboard buffer (which in your example will require 14 bytes), but since you are passing the BYTE count as a CHARACTER count to wcscpy_s(), you are telling it that the clipboard buffer can hold up to 14 wchar_t elements, when in actuality it can hold only 7. You are giving wcscpy_s() permission to go out of bounds of the clipboard buffer (for instance, if it wants to pre-fill the buffer memory before then filling it with actual characters). Doing so would corrupt the call stack, which could easily cause an exception when main() exits.
You need to pass wcscpy_s() the max number of CHARACTERS that the clipboard buffer can hold. Not the max number of BYTES it can hold.
You can do that by dividing iSize by sizeof(wchar_t), eg:
wcscpy_s(wpchData, iSize / sizeof(wchar_t), wcSource);
Alternatively, since you are using the exact BYTE size of the source array to allocate the clipboard buffer, you can use _countof() to get the number of CHARACTERS in the array (you cannot pass the allocated clipboard buffer to _countof()), eg:
wcscpy_s(wpchData, _countof(wcSource), wcSource);
Alternatively, you can use wsclen() instead, eg:
wchar_t wcSource[] = L"Testeu";
int iLen = wcslen(wcSource) + 1;
UINT iSize = iLen * sizeof(wchar_t);
...
hClipboardData = GlobalAlloc(GMEM_DDESHARE, iSize);
...
wcscpy_s(wpchData, iLen, wcSource);

mbstowcs_s function retsize sometimes return input length + 1

I'm using VisualStdio 2010 on Windows 7.
I want to decrypt password using function and display result of decryption as TCHAR*.
Implementation here,
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
char* _decrypt_password_v1(const char* strPassword);
char Hash_v1(const char chhash, int nIndex);
#define VIT_PASSWORD _decrypt_password_v1("OOWIEJFOISJDFNPPAJ")
char* _decrypt_password_v1(const char* strPassword)
{
unsigned int i = 0;
char* strDecrypt = (char*)malloc(strlen(strPassword) + 1);
memset(strDecrypt, 0x00, strlen(strPassword) + 1);
int nLen = strlen(strPassword) -1;
for (int i = 0; i < nLen; i++)
{
strDecrypt[i] = Hash_v1(strPassword[nLen - i], nLen - 1);
}
strDecrypt[i] = NULL;
return strDecrypt;
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szPassword[MAX_PATH] = {0};
int nLen = strlen(VIT_PASSWORD);
_tprintf(_T("Input Password Len : %d\n"), nLen);
size_t outSize;
mbstowcs_s(&outSize, szPassword, strlen(VIT_PASSWORD), VIT_PASSWORD, strlen(VIT_PASSWORD));
_tprintf(_T("Password : %s\n"), szPassword);
return 0;
}
If I run this code, I will get an error
Debug Assertion Failed!
File: f:\dd\vctools\crt_bld\self_x86\crt\src\mbstowcs.c
Line: 283
Expression: retsize <= sizeInWords
So, I increased parameter 3 of mbstowcs_s tostrlen(VIT_PASSWORD) + 1.
Corrected code:
mbstowcs_s(&outSize, szPassword, strlen(VIT_PASSWORD) + 1, VIT_PASSWORD, strlen(VIT_PASSWORD));
Then no crash and run correctly, but sizeInWords is strlen(VIT_PASSWORD), not strlen(VIT_PASSWORD) + 1.
If I use mbstowcs instead, there's no error. like this mbstowcs(szPassword, VIT_PASSWORD, strlen(VIT_PASSWORD));
Why this happens? If the answer is not clear, I have to modify this part of my entire code in this way.
I need concrete answers.
The third parameter to mbtowcs_s should be the size of the buffer pointed to by the second parameter in wchar_ts, so in your case it should be MAX_PATH.
The point of mbtowcs_s is to make sure you don't write more characters to the destination than you have space for. That's what the third parameter is for: to tell it how much space you have. In this case, if VIT_PASSWORD has no non-ASCII characters in it, the destination will need the same number of wchar_ts to hold the converted string. So if VIT_PASSWORD is 4 characters long, plus the nul terminator, then mbtowcs_s's third parameter will need to be at least 5 to successfully convert the string (4 characters plus the nul-terminator). The problem is that strlen(VIT_PASSWORD) will return 4, not 5 since it doesn't count the nul-terminator.

Cannot properly memcpy a char array to struct

So I have a construct called packet
struct Packet {
unsigned int packet_type;
wchar_t packet_length[128];
wchar_t file_name[256];
wchar_t template_name[256];
wchar_t file_name_list[1024];
wchar_t file_data[1024];
void serialize(char * dat) {
memcpy(dat, this, sizeof(Packet));
}
void deserialize(const char * dat) {
memcpy(this, dat, sizeof(Packet));
}
};
I'm trying to desieralize from this data
{byte[2692]}
[0] 0 unsigned int packet_type; (4 bytes)
[1] 0
[2] 0
[3] 0
[4] 50 '2' wchar_t packet_length[128]; (128 bytes)
[3] 0
[5] 54 '6'
[3] 0
[6] 57 '9'
[3] 0
[7] 50 '2'
[8] 0
[...] 0
[132] 112 'p' wchar_t file_name[256]; (256 bytes)
[133] 0
[134] 104 'h'
[...] 0
But the memcpy in deserialze isn't giving me the file_name, but it does give me the packet_length. What's up with this? Thanks!
EDIT:
So it's clear to me now that wchar_t is taking up more space than I once thought; however, I'm being told not to use memcpy at all?
I've written this deserialize method and it grabs the data correctly. Will this still cause a security leak?
void deserialize(const char * dat) {
memcpy(&(packet_type), dat, 4);
memcpy(&(packet_length[0]), dat + 4, 128);
memcpy(&(file_name[0]), dat + 132, 256);
memcpy(&(template_name[0]), dat + 388, 256);
memcpy(&(file_name_list[0]), dat + 644, 1024);
memcpy(&(file_data[0]), dat + 1668, 1024);
}
Please do not use this method for serializing structures. It's utterly non-portable.
Moreover, the compiler might as well pad, align or reorder members depending on the target architecture, endianness, optimizations and a bunch of other things.
A much more elegant way would be to use boost::Serialization, which takes care of low-level details in a portable way.
If, on the other hand, you just want to inspect your structures, then a debugger comes handy...
The layout of your char array assumes that the size of wchar_t is two bytes; it is not - here is an example of a system where the size of wchar_t is 4, so the size of Packet is 10756, not 2692 bytes: (link to a demo).
That is why your memcpy trick from the edit presents a problem: it assumes that the layout of data in the char[] array matches the layout of wchar_t[] arrays, which it may or may not match. If you know that your data array has two-character elements stored in little endian format (LSB first), you can write your own function that converts the data from the source to the destination, and call it for portions of your serialized data, like this:
void bytes_to_wchar(wchar_t *dest, const unsigned char* src, size_t length) {
for (size_t i = 0 ; i != lengt ; i++) {
dest[i] = src[2*i] | (src[2*i+1] << 8);
}
}
Now you can use this function to copy data into wchar_t arrays independently of the wchar_t size on the target system, or the endianness of the target system:
void deserialize(const char * dat) {
bytes_to_wchar(packet_type, dat + 0, 4);
bytes_to_wchar(packet_length[0], dat + 4, 128);
bytes_to_wchar(file_name[0], dat + 132, 256);
bytes_to_wchar(template_name[0], dat + 388, 256);
bytes_to_wchar(file_name_list[0], dat + 644, 1024);
bytes_to_wchar(file_data[0], dat + 1668, 1024);
}
The shortcut of saving the data from memory and writing it back may work when you do it on the same hardware, using the same compiler. Even then it remains sensitive to small adjustments in the headers that you use and in the settings of the compiler.
If the character array that you need to copy into the struct has a fixed layout, you need to write a function to process that layout, converting two-byte groups into wchar_ts, four-byte groups into unsigned ints, and so on.

How to zlib compress a QByteArray?

I would like to maintain interoperability between every other application on the planet (including web applications) when compressing text. Since qCompress and qUncompress seem to go against the grain, I'm trying to use zlib directly from my Qt application.
I will accept the simplest (most minimal) answer that shows me how to use the zlib library with a QByteArray directly OR modify the output of qCompress so that it can be used outside of a Qt application.
Here's my embarrassing attempt:
QByteArray tdata = QString("Oh noes!").toUtf8();
QByteArray cdata;
uLongf len = 12 + 1.002*tdata.length();
compress(&cdata, &len, &tdata, tdata.length());
And the error:
error: cannot convert 'QByteArray*' to 'Bytef*' for argument '1' to 'int compress(Bytef*, uLongf*, const Bytef*, uLong)'
Then I tried using QByteArray::constData()
compress(cdata.constData(), &len, &tdata, tdata.length());
But got the following error:
error: invalid conversion from 'const char*' to 'Bytef*'
I have no idea what a Bytef is so I start looking in the zlib sources to investigate. But all I can find for this is in QtSources/src/3rdparty/zlib/zconf.h
# define Bytef z_Bytef
So now I'm just lost.
Based on this note in qUncompress, I think it's pretty easy.
Note: If you want to use this function to uncompress external data that was compressed using zlib, you first need to prepend a four byte header to the byte array containing the data. The header must contain the expected length (in bytes) of the uncompressed data, expressed as an unsigned, big-endian, 32-bit integer.
So you can probably just compress it like this:
QByteArray tdata = QString("Oh noes!").toUtf8();
QByteArray compressedData = qCompress(tdata);
compressedData.remove(0, 4);
Here is some code I once wrote which gets as input a pointer to a byte array, the number of bytes to compress and the compression level and then uses zlib to compress the input. The result is returned in a string.
enum compressionLevel
{
clFast,
clSmall,
clDefault
};
const size_t ChunkSize = 262144; //256k default size for chunks fed to zlib
void compressZlib(const char *s, size_t nbytes, std::string &out, compressionLevel l /*= clDefault*/ )
{
int level = Z_DEFAULT_COMPRESSION;
switch (l)
{
case clDefault:
level = Z_DEFAULT_COMPRESSION; break;
case clSmall:
level = Z_BEST_COMPRESSION; break;
case clFast:
level = Z_BEST_SPEED; break;
};
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int ret = deflateInit(&strm, level);
if (ret != Z_OK)
{
throw std::runtime_error("Error while initializing zlib, error code "+ret);
}
size_t toCompress = nbytes;
char *readp = (char*)s;
size_t writeOffset = out.size();
out.reserve((size_t)(nbytes * 0.7));
while (toCompress > 0)
{
size_t toRead = std::min(toCompress,ChunkSize);
int flush = toRead < toCompress ? Z_NO_FLUSH : Z_FINISH;
strm.avail_in = toRead;
strm.next_in = (Bytef*)readp;
char *writep = new char[ChunkSize];
do{
strm.avail_out = ChunkSize;
strm.next_out = (Bytef*)writep;
deflate(&strm, flush);
size_t written = ChunkSize - strm.avail_out;
out.resize(out.size() + written);
memcpy(&(out[writeOffset]), writep, written);
writeOffset += written;
} while (strm.avail_out == 0);
delete[] writep;
readp += toRead;
toCompress -= toRead;
}
(void)deflateEnd(&strm);
}
Maybe this helps you to solve your problem, I guess using the cdata.constData() you can directly call this function
Just to help you out with the last section of your question here:
I have no idea what a Bytef is so I start looking in the zlib sources to investigate.
For the definitions of Byte and Bytef, look at lines 332 and 333 of zconf.h, as well as line 342:
332 #if !defined(__MACTYPES__)
333 typedef unsigned char Byte; /* 8 bits */
...
338 #ifdef SMALL_MEDIUM
339 /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
340 # define Bytef Byte FAR
341 #else
342 typedef Byte FAR Bytef;
The definition of FAR is for mixed-mode MSDOS programming, otherwise it is not defined as anything (see lines 328-330 of zconf.h).
Thus the zlib typedefs Bytef and Byte are basically the same as unsigned char on most platforms. Therefore you should be able to-do the following:
QByteArray tdata = QString("Oh noes!").toUtf8();
QByteArray cdata(compressBound(tdata.length()), '\0');
uLongf len = compressBound(tdata.length());
compress(reinterpret_cast<unsigned char*>(cdata.data()), &len,
reinterpret_cast<unsigned char*>(tdata.data()), tdata.length());