C++ char-array parameter contains weird characters on x86 compile - c++

I'm quite new to C++ and I have to implement a Polybius cipher function.
I passed a char c-array as a parameter to my function.
I used a dummy string of "PROG" to test the code and it works perfectly when I compile it in x64(which was set as default by Visual Studio 2015 for some reason). However if I pass the array to the function in a x86 build, it contains weird characters for no appearant reason:
"PROG\x190§ÎæÏX1"
Heres my code:
void createPolybiusMatrix(const char keyphrase[]) {
//Keyphrase contains "PROG" on x64 but "PROG\x190§ÎæÏX1" on x86!
//Do Stuff
}
int main() {
char passphrase[] = {'P','R','O','G'};
//Everythings fine here, passphrase contains "PROG" on both platforms.
createPolybiusMatrix(passphrase);
return 0;
}
Any ideas? I'm still quite new to C++ and this confuses me like hell!?

C strings need to be null-terminated. In order for your program to work correctly, you need to use:
char passphrase[] = {'P','R','O','G','\0'};

The char array is not null-terminated, so if the byte following 'G' is not 0, you'll overflow and print out garbage. This is technically undefined behavior.
To print the char array as you would a string, you need to null-terminate it.

Related

Coverity issue: Copy of overlapping memory (OVERLAPPING_COPY) on sprintf statement

char arr[512];
...
sprintf(arr, "%s %30s", arr, "Some Text");
I'm getting the following message for the sprintf statement:
In the call to function sprintf, the arguments arr and arr may point to the same object.
Is there another way to implement this kind of formatting?
This code code contains two unrelated errors. As for the PVS-Studio analyzer, it issues two following warnings:
V576 Incorrect format. A different number of actual arguments is expected while calling 'sprintf' function. Expected: 4. Present: 3. test.cpp 54
V541 It is dangerous to print the 'arr' string into itself. test.cpp 54
The first one implies that the function is passed insufficient number of actual arguments. Indeed, the format string indicates that a string and an integer number are expected as arguments. But only a string is passed. There is no numeric argument, resulting in the usage of an amount of memory with a random value and consequently undefined behavior.
The second warning tells us that there is no guarantee that the sprintf function works correctly if one buffer is used as an input and output buffer. Such code might work correctly or it might not. It all depends on the implementation of the sprintf function. In any case, there is no reason to write code in such a way.
Therefore, Coverity is absolutely right when issuing the warning for this code. The code is definitely incorrect.
P.S. It reminded me of another funny case related to the usage of a "fake sprintf" :).
The overlapping warning has to do with the fact that you are copying arr to itself, thus overwriting it's content.
Furthermore in the code:
sprintf(arr, "%s %0x", arr);
^^^
%s takes the arr string, but %0x doesn't take an unsigned hexadecimal integer variable as it should, so you are probably missing a parameter.
Something along the lines of:
char arr[512];
char arr2[1024];
unsigned int x = 15;
sprintf(arr2, "%s %0x", arr, x);

C++ Convert int to wchar_t*

So I've been trying to convert integer values to wchar_t*. This is the test I run so I could simplify it as much as I can.
int test=123;
wchar_t *testc[12][12];testc[0][0]=L"hello";
_itow(test,testc[0][0],10);
wcout<<testc[0][0];
This code right here compiles but also gives me the Not Responding error of doom.
What is VERY strange for my understanding is why this
int test=123;
wchar_t *testc[12][12];testc[0][0]=L"hello";
_itow(test,testc[1][0],10);
wcout<<testc[0][0]<<testc[1][0];
Works without any problem, and showing the output "hello123" just as intended.
Any idea why this happens?
My project has some occurrences similar to the first code shown (except the wcout part), thus I want to understand why they give me the Not Responding state.
Main issue with your code is not allocating memory for testc[1][0].
Also it will be better to use standard c++ functions like std::to_wstring instead of _itow.
So here is sample code for your problem :
int main()
{
int test=123;
wchar_t *testc[12][12];
testc[0][0]=L"hello";
testc[1][0] = new wchar_t[4];
std::wstring temp = std::to_wstring(123);
for(int i=0;i<temp.length();i++)
{
testc[1][0][i] = temp[i];
}
wcout<<testc[0][0]<<testc[1][0];
return 0;
}
This is just sample code and i am assuming in your program you are taking care of memory allocation and deallocation

C++ Arduino, use of sprintf inside a method with a char pointer parameter, breaks program

I have worked for most of the day on this problem and have narrowed it down to the following simple program to replicate it:
Test.ino
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(9600);
}
// the loop function runs over and over again until power down or reset
void loop() {
char _message[16] = { '\0' };
char *message = _message;
int pins[1] = { 1 };
//testOne(pins, 35, 5); // WORKS!!
testTwo(pins, 35, 5, message); // Desn't Work...
}
void testOne(int sensorPins[], int userDefault, int offset) {
char _int_char[2];
sprintf(_int_char, "%d", 36);
Serial.println(_int_char);
}
void testTwo(int sensorPins[], int userDefault, int offset, char *message) {
char _int_char[2];
sprintf(_int_char, "%d", 37);
Serial.println(_int_char);
}
All the above code does is call the testOne and testTwo functions.
The testOne function gives the expected outcome of the value of 36 being written to the serial window for each iteration of the loop.
The testTwo function writes the following to the serial window:
"VMDPV_1|1_VMVMDPV_1|1_VM".....
This only happens when I add the char *message parameter to the function.
Obviously this is a very simplified demo with hard coded values etc... in my actual code I make use of the parameters and there is a lot more going on...
It is actually the call to sprintf that causes the issues. In my actual code I use this as a part of building up the message. When I comment out the sprintf line in my actual code it works. But of course I need that line to get the value of one of the parameters into the message.
Can anyone out there tell me why sprintf doesn't work in a function that has a char *message param?
I am using an Arduino UNO and have written the code in Visual Studio using Visual Micro 1511.23.1, which does it's bulid based on the installed arduino IDE setup which is 1.6.5.
I have been able to replicate this in the arduino IDE as well, except I get different characters than "VMDPV_1..."... I got a, 3 a letter O with a upside down comma on top and a square.
I am developing all this on a Win 10 64bit PC.
Thanks for your time,
Scott
Your program produces undefined behavior due to a buffer overrun.
char _int_char[2];
sprintf(_int_char, "%d", 37); // <-- buffer overrun
Since the resulting string may occupy more than 2 characters, the excess characters overflow the _int_char array and will overwrite memory. What is at the overwritten memory before the corruption may have something to do with the parameter message.
Instead of creating a 2 character array, declare the array big enough to not produce a buffer overflow.
char _int_char[20];
sprintf(_int_char, "%d", some_integer);
Unless you have integers that have more than 19 digits, this should now not overflow the buffer.
A foolproof solution, since you're using C++, is to use C++ streams, namely std::ostringstream. Then you need not worry about buffer overruns, regardless of the length of the data to be outputted:
#include <sstream>
#include <string>
//...
std::string _int_char;
std::ostringstream strm;
strm << some_integer;
_int_char << strm.str();
In C strings are 0-terminated, meaning that after the call to sprintf, _int_char contains { '3', '6', '\0' }. This is an array of 3 chars and you only reserver memory for 2
char _int_char[2];
sprintf(_int_char, "%d", 36);

Expected behaviour when assigning std::string to non-terminated char array?

I'm working on C++ code developed by other people, and have found a section where a std::string is assigned to a char array which is not null-terminated. The code (simplified) is something like this:
char *filePath="c:\\filename.txt"; //file known to contain 20 chars per line.
int size=20;
char *buffer;
std::string bufferstr;
buffer=new char[size];
std::ifstream input(filePath, std::ios::in | std::ios::binary);
input.read(buffer,size);
bufferstr=buffer; // Assign string to non-null-terminated char array.
// Lots of other code omitted here.
input.close();
delete[] buffer;
I'm not surprised to find memory errors when checking the code with Dr. Memory, and have now changed this so that buffer is always null-terminated, but the code has had this error for about 3 years and has behaved as intended (on Windows, Linux, and Solaris) until I recently made changes in a seemingly unrelated part of the code.
My questions are:
- What is the expected behaviour when assigning a std::string to a non-null-terminated char array?
- Why would this code have started misbehaving after I made changes elsewhere?
If the char array is non-null-terminated the result is UB. What is likely to happen is that string constructor will go beyond the allocated buffer and encounter a null byte sooner or later.
What is the expected behaviour when assigning a std::string to a non-null-terminated char array?
std::string will consider everything from the pointer received to the first address containing a zero value, to be part of the string. Usually, this means you either get a few garbage characters at the end of your string, or you get an application core dump, with an error like "unable to allocate " or "access violation reading ".
Why would this code have started misbehaving after I made changes elsewhere?
Because your changes elsewhere, also changed where zeros were, in the memory adjacent to the end of your non-zero terminated buffer (this is an educated guess).

sprintf_s crashes

I am getting a crash while executing the following code ocassionally at sprintf_s. This code was working many years without any problems. When I gave the size in strcat_s and sprintf_s as in the statements below, the crash is not appearing. What could be the reason for this?
strcat_s(sztmpCurrDate,100,sztmpCurrTime);
sprintf_s(sztmpCurrDate,100,"%s:%0.3d",sztmpCurrDate,curTime.wMilliseconds););
char sztmpCurrDate[100] = "";
char sztmpCurrTime[100] = "";
SYSTEMTIME curTime;
GetLocalTime(&curTime);
GetLocalTime(&curTime);
GetDateFormat(LOCALE_USER_DEFAULT,
DATE_SHORTDATE,
&curTime,
NULL,
sztmpCurrDate,
100);
GetTimeFormat(LOCALE_USER_DEFAULT,
TIME_FORCE24HOURFORMAT,
&curTime,
"HH':'mm':'ss",
sztmpCurrTime,
100);
strcat_s(sztmpCurrDate," ");
strcat_s(sztmpCurrDate,sztmpCurrTime);
sprintf_s(sztmpCurrDate,"%s:%0.3d",sztmpCurrDate,curTime.wMilliseconds);
From the documentation for sprintf_s:
If copying occurs between strings that overlap, the behavior is undefined.
Your code:
sprintf_s(sztmpCurrDate,"%s:%0.3d",sztmpCurrDate,curTime.wMilliseconds);
copies from the source to the destination sztmpCurrDate. Also, you haven't specified the size of the destination string, which is required by sprintf_s (I don't know how your code even compiled like that). Try:
sprintf_s(sztmpCurrDate + strlen(sztmpCurrDate), 100-strlen(sztmpCurrDate),
":%0.3d",curTime.wMilliseconds);
A better approach, since you're using C++, is to use std::string and then you won't have to worry about this sort of C string manipulation error.
Wrong syntax!!!
Second argument of sprintf_s is length of your buffer and in your case when program crashes you provided pointer to C string (char *). This is absolutely syntax error.
The compiler probably issued a warning, but sadly has let this pass. This is because sprintf_s takes three arguments + variable number of arguments. In your wrong case you provided three arguments so the compiler was satisfied, but he treated your "format string" as "number of arguments" and sztmpCurrDate as "format string".
If you used any other function with fixed number of arguments and you provided less than needed this would be a compile error.
You are probably using the incorrect version:
sprintf_s(sztmpCurrDate,"%s:%0.3d",sztmpCurrDate,curTime.wMilliseconds);
Instead it should be:
int slen = strlen(sztmpCurrDate) + 1;
sprintf_s(sztmpCurrDate, slen, "%s:%0.3d",sztmpCurrDate,curTime.wMilliseconds);
Refer to this sprintf_s for more information.
The code worked correctly, the code is not correct.
sprintf(sztmpCurrDate,"%s:%0.3d",sztmpCurrDate,curTime.wMilliseconds);
Rewrite as
sprintf(&sztmpCurrDate[strlen(sztmpCurrDate)],"%0.3d",curTime.wMilliseconds);
And for home work tell us why .....