My code:
m_ListCtrlCandidates.InsertItem(i, _itoa_s(candidate[i].ID, (char*)(LPCTSTR)str, 10));
m_ListCtrlCandidates.SetItemText(i, 1, _itoa(candidate[i].FingerNumber, (char*)(LPCTSTR)str, 10));
m_ListCtrlCandidates.SetItemText(i, 2, _itoa(candidate[i].SampleNumber, (char*)(LPCTSTR)str, 10));
m_ListCtrlCandidates.SetItemText(i, 3, _itoa(candidate[i].ConfidenceLevel, (char*)(LPCTSTR)str, 10));
Error:
Error 2 error C4996: '_itoa': This function or variable may be unsafe. Consider using _itoa_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. d:\documents\visual studio 2013\projects\gatekeeper\gatekeeper\gatekeeperdlg.cpp 416 1 Gatekeeper
I'm using an SDK that has the following code in their sample. It adds potential matches to a list in the dialog. Initially I had my project set to unicode and updated the code to work. This was giving me trouble so I looked at the sample code and it's character set was blank. So I changed mine and now I get this error.
If I switch it to _itoa_s I get the error that the function doesn't take 3 arguments. So I guess I'm missing the size argument, but I'm not sure what size it is suppose to be. Also, it compiles fine in their sample code when left as _itoa.
I'd really like to keep it in Unicode. Using _wtoi instead of atoi helped in other places. Is there something similar for this case?
I'm using an SDK that has the following code in their sample.
That's unfortunate!
_itoa(candidate[i].FingerNumber, (char*)(LPCTSTR)str, 10)
I'm guessing that you're using MFC, str
is a CString
, and you're calling CListCtrl::SetItemText
.
The (LPCTSTR)
operator on CString
gets the pointer to the underlying buffer holding the string data. That's a const TCHAR*
, so if you're compiling in ANSI mode, this is a const char*
pointer to bytes; in Unicode mode it's a const wchar_t*
point to 16-bit code units.
Casting this to a non-const char*
and asking _itoa
to write to that is a pretty bad idea. This overwrites whatever was originally in the CString
, and if the number is big enough that the resulting string is longer than what was originally in the CString
you could be writing over the end of the array, causing memory corruption havoc.
Casting it to a char*
in Unicode mode is even weirder as you're using a wchar_t
array as storage for char*
bytes. And SetItemText()
in Unicode mode would be expecting to get wchar_t
characters instead surely?
Using _wtoi instead of atoi helped in other places. Is there something similar
_itow
exists as the wchar_t
analogue of _itoa
. (At least in VS. Neither function is standard C[++] as such.)
You can switch on #ifdef _UNICODE
and call either _itoa
or _itow
to match whichever type TCHAR
is. But unless you really need to support an ancient ANSI-only build for some legacy reason there's not much reason to bother with TCHAR
switching these days. You can usually just stick to Unicode mode and use wchar_t
-based strings for text.
error C4996: '_itoa': This function or variable may be unsafe.
Microsoft deprecated a number of C functions that write variable amounts of content to pre-allocated buffers, because the buffers can easily be too short, resulting in the aforementioned memory corruption horror. This has been a cause of countless security problems in applications in the past, so it's best avoided.
Unfortunately warning 4996 actually deprecates some standard functions that aren't really dangerous too, which is quite tiresome, especially as the _s
versions suggested as a replacement are typically not supported by other compilers.
In this case though MS are kind of right, _itoa
isn't really safe. To use it safely you'd have to allocate a buffer large enough for the longest possible integer of the type you're passing, and it's really easy to get that wrong.
If I switch it to _itoa_s I get the error that the function doesn't take 3 arguments. So I guess I'm missing the size argument, but I'm not sure what size it is suppose to be
It's however many elements are available at the end of the pointer to write to. So at present that would depend on the length of the CString
whose buffer you're stealing. But it's not a good idea to do that. You could allocate your own buffer:
wchar_t str[8];
_itow_s(candidate[i].FingerNumber, str, 8, 10);
This is safe, though it still fails (with errno EINVAL
) if FingerNumber has more than 7 digits as there would be no space to store them all (including the \0
terminator).
Functions like itoa
that write variable content to buffers are pretty ugly in general. If you can use modern C++ with the STL, there are simpler, safer string-handling methods available, for example:
#include <string>
std::wstring fingers = std::to_wstring(candidate[i].FingerNumber);
m_ListCtrlCandidates.SetItemText(i, 1, fingers.c_str());
(although how well this will mix with old-school MFC and CString is another question.)