in debug it works fine but when I run the C++ 2010 program in release build (not started from the debugger of visual studio) it crashes. If I comment the lines after the second char*-wchar* conversion it works. Why?
void myfunction(const char *dataBuffer)
{
size_t buffer_size;
mbstowcs_s(&buffer_size, NULL, 0, dataBuffer, _TRUNCATE);
wchar_t *buffer = new wchar_t[buffer_size + 1];
mbstowcs_s(&buffer_size, buffer, buffer_size, dataBuffer, _TRUNCATE);
std::wstring archive_data(buffer);
std::wstringstream archive_stream(archive_data);
boost::archive::text_wiarchive archive(archive_stream);
...
delete [] buffer;
buffer = NULL;
}
Probably because of an uninitialized variable (in debug mode most variables are Initialized to zero but are uninitialized in release)
Most bugs like this can be fixed by fixing all the warnings generated by the compiler (warnings are really logical errors rather than syntax errors). So set you warning level higher re-compile make sure you get zero wanings.
In dev studio set the warning level to four, also set the flag to treat warnings as errors.
Ps. Rather than dynamically allocating a buffer with
wchar_t* buffer = new char_t [<size>];
Use a standard vector (it's exception safe)
std::vector<wchar_t> buffer(<size>);
You can get a pointer to the buffer with:
&buffer[0]
Also: Jen (who deleted his answer) has a good point )I'll delete this and up-vote Jen if he un-deletes his answer.
But you may want to check that the string is correctly NULL terminated L'\0'.
Sometimes compiler attempts to optimize the values which may not allowed to change in the middle of the program.
To notify the compiler to avoid optimization for the particular variable declare as
volatile variable.
Related
GCC 8 added a -Wstringop-truncation warning. From https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82944 :
The -Wstringop-truncation warning added in GCC 8.0 via r254630 for bug 81117 is specifically intended to highlight likely unintended uses of the strncpy function that truncate the terminating NUL charcter from the source string. An example of such a misuse given in the request is the following:
char buf[2];
void test (const char* str)
{
strncpy (buf, str, strlen (str));
}
I get the same warning with this code.
strncpy(this->name, name, 32);
warning: 'char* strncpy(char*, const char*, size_t)' specified bound 32 equals destination size [-Wstringop-truncation`]
Considering that this->name is char name[32] and name is a char* with a length potentially greater than 32. I would like to copy name into this->name and truncate it if it is greater than 32. Should size_t be 31 instead of 32? I'm confused. It is not mandatory for this->name to be NUL-terminated.
This message is trying to warn you that you're doing exactly what you're doing. A lot of the time, that's not what the programmer intended. If it is what you intended (meaning, your code will correctly handle the case where the character array will not end up containing any null character), turn off the warning.
If you do not want to or cannot turn it off globally, you can turn it off locally as pointed out by #doron:
#include <string.h>
char d[32];
void f(const char *s) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
strncpy(d, s, 32);
#pragma GCC diagnostic pop
}
This new GCC warning renders strncpy() mostly unusable in many projects: Code review will not accept code, that produces warnings. But if strncpy() is used only with strings short enough, so that it can write the terminating zero byte, then zeroing out the destination buffer in the beginning and then plain strcpy() would achieve the same job.
Actually, strncpy() is one of the functions, that they had better not put into the C library. There are legitimate use cases for it, sure. But library designers forgot to put fixed size string aware counterparts to strncpy() into the standard, too. The most important such functions, strnlen() and strndup(), were only included 2008 into POSIX.1, decades after strncpy() was created! And there is still no function, that copies a strncpy() generated fixed-length string into a preallocated buffer with correct C semantics, i.e. always writing the 0-termination byte. One such function could be:
// Copy string "in" with at most "insz" chars to buffer "out", which
// is "outsz" bytes long. The output is always 0-terminated. Unlike
// strncpy(), strncpy_t() does not zero fill remaining space in the
// output buffer:
char* strncpy_t(char* out, size_t outsz, const char* in, size_t insz){
assert(outsz > 0);
while(--outsz > 0 && insz > 0 && *in) { *out++ = *in++; insz--; }
*out = 0;
return out;
}
I recommend to use two length inputs for strncpy_t(), to avoid confusion: If there was only a single size argument, it would be unclear, if it is the size of the output buffer or the maximum length of the input string (which is usually one less).
There are very little justified case for using strncpy. This is a quite dangerous function. If the source string length (without the null character) is equal to the destination buffer size, then strncpy will not add the null character at the end of the destination buffer. So the destination buffer will not be null terminated.
We should write this kind of code on Linux:
lenSrc = strnlen(pSrc, destSize)
if (lenSrc < destSize)
memcpy(pDest, pSrc, lenSrc + 1);
else {
/* Handle error... */
}
In your case, if you want to truncate the source on copy, but still want a null terminated destination buffer, then you could write this kind of code:
destSize = 32
sizeCp = strnlen(pSrc, destSize - 1);
memcpy(pDest, pSrc, sizeCp);
pDest[sizeCp] = '\0';
Edit: Oh... If this not mandatory to be NULL terminated, strncpy is the right function to use. And yes you need to call it with 32 and not 31.
I think you need to ignore this warning by disabling it... Honestly I do not have a good answer for that...
Edit2: In order to mimic the strncpy function, you could write this code:
destSize = 32
sizeCp = strnlen(pSrc, destSize - 1);
memcpy(pDest, pSrc, sizeCp + 1);
TL;DR: handle the truncation case and the warning will dissappear.
This warning happened to be really useful for me, as it uncovered an issue in my code. Consider this listing:
#include <string.h>
#include <stdio.h>
int main() {
const char long_string[] = "It is a very long string";
char short_string[8];
strncpy(short_string, long_string, sizeof(short_string));
/* This line is extremely important, it handles string truncation */
short_string[7] = '\0';
printf("short_string = \"%s\"\n", short_string);
return 0;
}
demo
As the comment says short_string[7] = '\0'; is necessary here. From the strncpy man:
Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
If we remove this line, it invokes UB. For example, for me, the program starts printing:
short_string = "It is a It is a very long string"
Basically, GCC wants you to fix the UB. I added such handling to my code and the warning is gone.
The responses from others led me to just write a simple version of strncpy.
#include<string.h>
char* mystrncpy(char* dest, const char*src, size_t n) {
memset(dest, 0, n);
memcpy(dest, src, strnlen(src, n-1));
return dest;
}
It avoids the warnings and guarantees dest is null terminated. I'm using the g++ compiler and wanted to avoid pragma entries.
I found this while looking for a near-perfect solution to this problem. Since most of the answers here describing the possibility and ways about how to handle without suppressing the warning. The accepted answer suggests the use of the following wrapper which results in another set of warnings and is frustrating and not desirable.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
...
#pragma GCC diagnostic pop
Instead, I found this working solution, can't say if there are any pitfalls, but it does the work nicely.
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"")
strncpy(d, s, 32);
_Pragma("GCC diagnostic pop")
See full article here.
I found the best way to suppress the warning is to put the expression in parentheses like this gRPC patch:
(strncpy(req->initial_request.name, lb_service_name,
GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH));
The problem with #pragma diagnostics suppression solution is that the #pragma itself will cause a warning when the compiler does not recognize either the pragma or the particular warning; also it is too verbose.
What it say is that we can only use len - 1 characters because last one should be '\0', so use seems to clean the warning we only can copy len - 1 ...
by the examples:
strncpy(this->name, name, 31);
or
#include <string.h>
char d[32];
void f(const char *s) {
strncpy(d, s, 31);
}
d[31] = '\0';
I'm writing a Win32 console application in Visual Studio 2010.
Consider one function that take two char* as parameters.
Following is prototype of function:
void WriteApplicationFile(char *mappname,char* MessageString)
{
//Do some File related stuffs.
}
Now the following calls are working perfectly:
WriteApplicationFile("FirstOne", "Append Me");
WriteApplicationFile("FirstOne", "Append Another");
But if I try the same thing with some character array thing this will give me assertion, and throw me on assembly.
The following code is not working:
char * LocalBuffer = new char[100];
sprintf(LocalBuffer,"Number of jobs in Queue %d",JobsCount);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer);
LocalBuffer = NULL;
//Work fine.
//...
LocalBuffer = new char[100];
sprintf(LocalBuffer,"Log file name %s",LogFileCharName);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer); // I got assertion here..
LocalBuffer = NULL;
Where am I going wrong?
One more thing is that I want to handle all assertion and bugs with try-catch block. How would I do this?
If use new[] you must use delete[], not free() or delete. Replace:
free(LocalBuffer);
with:
delete[] LocalBuffer;
There appears to be no reason to be dynamically allocating memory. The size of the buffer is a compile time constant, is not large (no stack overflow) and the buffer appears to not be required to live beyond the scope in which it was allocated.
As this is c++ strongly suggest using std::string which will handle dynamic memory management for you and std::ostringstream which is typesafe and avoids specification of fixed sized buffers instead of sprintf():
#include <sstream>
#include <string>
std::ostringstream out;
out << "Number of jobs in Queue " << JobsCount;
const std::string s(out.str());
If access to a c-style string is required use std::string::c_str().
Additionally, the argument types of WriteApplicationFile() are char*, not const char*, so passing a string literal to the function would be causing undefined behaviour if the function modifies the arguments.
First, are you programming in C or in C++. The code you present
looks like C, but you speak of a try/catch block, which can only
be C++.
In C++, use std::ostringstream and std::string. Any other
solution is simply incorrect.
In C, you should use snprintf, instead of sprintf. It is
almost impossible to use sprintf safely. (How many characters
are in LogFileCharName, for example.) And don't use dynamic
allocation when you don't have to. (That holds for C++ as
well; there should be no new or delete (nor malloc nor
free) in the code you show.
As to what is going wrong, there are at least two possible
problems in the code you show: you're allocating memory with
new[], but freeing it with free (undefined behavior), and
you're not checking the length of LogFileCharName before
calling sprintf, so you could be overwriting the end of the
buffer.
Could anyone tell me what's wrong with this part of my code? It crashes during execution.
void MainWindow::on_pushButton_clicked()
{
char * cstr = new char [ui->lineEdit->text().length()];
string costam;
costam=ui->lineEdit->text().toStdString();
strcpy(cstr, costam.c_str()); <<<----TROUBLE LINE
int z;
z=costam.length();
for(int n=0;n<z;n++){
string wynik;
wynik=konwersja(cstr[n]);
mors(wynik);
Sleep(300);
}
delete[] cstr;
}
When I try to compile it with MinGW in Qt 5.0.1 everything is OK but with MSVC2010 in Qt 4.8.1 there is a warning:
warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
Your question is wrong. This code compiles and there's nothing about QT here.
strcpy is deprecated because it's unsafe. Alternative is strcpy_s:
strcpy_s( cstr, ui->lineEdit->text().length() + 1, costam.c_str() );
Note that you should allocate ui->lineEdit->text().length() + 1, not ui->lineEdit->text().length(). That's the reason of crash, I guess.
BTW I see no reason to use cstr array in your code at all. As example:
void MainWindow::on_pushButton_clicked() {
string costam;
costam = ui->lineEdit->text().toStdString();
for( size_t n = 0; n < costam.length(); n++ ) {
string wynik;
wynik = konwersja( costam[ n ] );
mors( wynik );
Sleep( 300 );
}
}
Because people are not very aware of security when programming C++, and Windows gets a bad rap because of it, Visual Studio "deprecated" several functions which are common causes of buffer overflows. In this case you should be fine, and can probably just disable the warning by defining _CRT_SECURE_NO_WARNINGS. You may also find this issue with posix functions, too, in which case you would be able to disable those warnings with a separate #define.
Can you change this line strcpy(cstr, costam.c_str()); with strcpy_s(cstr, costam.c_str()); try compiling again?
Also it shouldn't prevent compiling, MSVC2010 is just warning about an unsafe usage. You can also lower the warning level of MSVC2010.
You have two problems here.
The crash is because strcpy will write length + 1 characters into the destination buffer, but your buffer is only of size length. The +1 is for the null termination character, which is not included in length.
The warning is because Microsoft believes its too easy to make mistakes using strcpy and discourages its use. As Joel mentioned, you could enable a define to prevent that warning. I would not recommend semihyagcioglu and Microsoft's suggestion of using strcpy_s, as it's not a portable solution.
I'd also like to note that while fixing those things will make your code compile and run without error, there are other questions. Like: why do you need the cstr variable in the first place? cstr[n] can probably be replaced with costam.data()[n]. Then the cstr variable won't need to exist at all. You won't need the new, delete or strcpy.
I'm working on VS 2010 express and trying to do some file reading and parsing work
my function goes something like this... (I dropped the boring parts)
void SomeClass::SomeFunc(char *ALName, std::map<...> *chromList, std::map<...> *chromLine)
{
ifstream file;
char tmpBuff[500];
char tmpBuff2[500];
char fileName[350];
char tmp[350];
char *pch;
char *pch2;
.....
file.open(fileName);
while ( file.getline( tmpBuff, 500 ) )
{
....
if ( some_condition == 0 )
{
pch2 = strtok( NULL, "," );
pch = strtok( NULL, "," );
(*chromList)[pch2] = do_some_work( atoi(pch), tmpBuff2 );
strcpy( tmp, get_chrom_line( tmpBuff2 ) );
(*chromLine)[pch2] = tmp;
}
}
file.close();
}
When I change to Release with Optimization set to Maximum speed this function is skipped.
The debugger enters the function and immediately returns.
When i run with Debug setting or Release with the Optimization flag set to disabled, the function runs just fine.
What can be the possible reason for that?
Can I put a preprocessor definition to force "No optimization" on this function while the rest of the code get optimized
Thanks!!
Idan
You should never try to debug optimized code. The line numbers it shows you will rarely match up with what is actually being executed, and forget about reading local variables. That is why there is a "Debug" and "Release" mode.
However, if you really want to, try this to make Visual Studio not optimize that function. You could also put that function in a separate source file and compile it in debug mode.
Are you sure that the function is actually being skipped and that the debugger isn't simply making it look skipped?
If it really isn't being executed then it's almost certain you have undefined behavior that happens to work how you want it when not optimized and the compiler (probably rightfully) optimizes it into non-working code in optimized mode.
That said I see some questionable items: You call strtok with NULL (aside - prefer 0 or nullptr in C++/C++11) without calling it with a valid pointer. Are you aware that strtok is destructive?
Then you use a character pointer to index an array, or presumably (hopefully?) call an overloaded operator[] function with a char* argument.
Since this is C++, your code will be cleaner, safer, and probably easier to debug if you remove all the C-style parsing and do it with string and find/find_first_of/etc depending on your needs.
I know there is a similarly titled question already on SO but I want to know my options for this specific case.
MSVC compiler gives a warning about strcpy:
1>c:\something\mycontrol.cpp(65): warning C4996: 'strcpy': This function or
variable may be unsafe. Consider using strcpy_s instead. To disable
deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
Here's my code:
void MyControl::SetFontFace(const char *faceName)
{
LOGFONT lf;
CFont *currentFont = GetFont();
currentFont->GetLogFont(&lf);
strcpy(lf.lfFaceName, faceName); <--- offending line
font_.DeleteObject();
// Create the font.
font_.CreateFontIndirect(&lf);
// Use the font to paint a control.
SetFont(&font_);
}
Note font_ is an instance variable. LOGFONT is a windows structure where lfFaceName is defined as TCHAR lfFaceName[LF_FACESIZE].
What I'm wondering is can I do something like the following (and if not why not):
void MyControl::SetFontFace(const std::string& faceName)
...
lf.lfFaceName = faceName.c_str();
...
Or if there is a different alternative altogether then let me know.
The reason you're getting the security warning is, your faceName argument could point to a string that is longer than LF_FACESIZE characters, and then strcpy would blindly overwrite whatever comes after lfFaceName in the LOGFONT structure. You do have a bug.
You should not blindly fix the bug by changing strcpy to strcpy_s, because:
The *_s functions are unportable Microsoft inventions almost all of which duplicate the functionality of other C library functions that are portable. They should never be used, even in a program not intended to be portable (as this appears to be).
Blind changes tend to not actually fix this class of bug. For instance, the "safe" variants of strcpy (strncpy, strlcpy, strcpy_s) simply truncate the string if it's too long, which in this case would make you try to load the wrong font. Worse, strncpy omits the NUL terminator when it does that, so you'd probably just move the crash inside CreateFontIndirect if you used that one. The correct fix is to check the length up front and fail the entire operation if it's too long. At which point strcpy becomes safe (because you know it's not too long), although I prefer memcpy because it makes it obvious to future readers of the code that I've thought about this.
TCHAR and char are not the same thing; copying either a C-style const char * string or a C++ std::string into an array of TCHAR without a proper encoding conversion may produce complete nonsense. (Using TCHAR is, in my experience, always a mistake, and the biggest problem with it is that code like this will appear to work correctly in an ASCII build, and will still compile in UNICODE mode, but will then fail catastrophically at runtime.)
You certainly can use std::string to help with this problem, but it won't get you out of needing to check the length and manually copy the string. I'd probably do it like this. Note that I am using LOGFONTW and CreateFontIndirectW and an explicit conversion from UTF-8 in the std::string. Note also that chunks of this were cargo-culted out of MSDN and none of it has been tested. Sorry.
void MyControl::SetFontFace(const std::string& faceName)
{
LOGFONTW lf;
this->font_.GetLogFontW(&lf);
int count = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
faceName.data(), faceName.length(),
lf.lfFaceName, LF_FACESIZE - 1)
if (count <= 0)
throw GetLastError(); // FIXME: use a real exception
lf.lfFaceName[count] = L'\0'; // MultiByteToWideChar does not NUL-terminate.
this->font_.DeleteObject();
if (!this->font_.CreateFontIndirectW(&lf))
throw GetLastError(); // FIXME: use a real exception
// ...
}
lf.lfFaceName = faceName.c_str();
No you shouldn't do that because you are making a local copy of the poitner to the data held inside the std::string. If the c++ string changes, or is deleted, the pointer is no longer valid, and if lFaceName decides to change the data this will almost certainly break the std::string.
Since you need to copy a c string, you need a 'c' function, then strcpy_s (or it's equivalent) is the safe alternative
Have you tried? Given the information in your post, the assignment should generate a compiler error because you're trying to assign a pointer to an array, which does not work in C(++).
#include <cstdio>
#include <string>
using namespace std;
struct LOGFONT {
char lfFaceName[3];
};
int main() {
struct LOGFONT f;
string foo="bar";
f.lfFaceName = foo.c_str();
return 0;
}
leads to
x.c:13: error: incompatible types in assignment of `const char*' to `char[3]'
I'd recommend using a secure strcpy alternative like the warning says, given that you know the size of the destination space anyway.
#include <algorithm>
#include <iostream>
#include <string>
enum { LF_FACESIZE = 256 }; // = 3 // test too-long input
struct LOGFONT
{
char lfFaceName[LF_FACESIZE];
};
int main()
{
LOGFONT f;
std::string foo("Sans-Serif");
std::copy_n(foo.c_str(), foo.size()+1 > LF_FACESIZE ? LF_FACESIZE : foo.size()+1,
f.lfFaceName);
std::cout << f.lfFaceName << std::endl;
return 0;
}
lf.lfFaceName = faceName.c_str(); won't work for two reasons (assuming you change faceName to a std:string)
The lifetime of the pointer returned by c_str() is temporary. It's only valid as long as the fileName object doesn't change and in alive.
The line won't compile. .c_str() returns a pointer to a char, and lfFaceName is a character array and can't be assigned to. You need to do something to fill in the string array, to fill in the bytes at lfFaceName, and pointer assignment doesn't do that.
There isn't anything C++ that can help here, since lfFaceName is a C "string". You need to use a C string function, like strcpy or strcpy_s. You can change your code to:
strcpy_s(lf.lfFaceName, LF_FACESIZE, faceName);