I'm using version xtea encryption from wikipedia that's written in C++. I wrote a function to encrypt a string
const char* charPtrDecrypt(const char* encString, int len, bool encrypt)
{
/********************************************************
* This currently uses a hard-coded key, but I'll implement
* a dynamic key based on string length or something.
*********************************************************/
unsigned int key[4] = { 0xB5D1, 0x22BA, 0xC2BC, 0x9A4E };
int n_blocks=len/BLOCK_SIZE;
if (len%BLOCK_SIZE != 0)
++n_blocks;
for (int i = 0; i < n_blocks; i++)
{
if (encrypt)
xtea::Encrypt(32, (uint32_t*)(encString + (i*BLOCK_SIZE)), key);
else
xtea::Decrypt(32, (uint32_t*)(encString + (i*BLOCK_SIZE)), key);
}
return encString;
}
It works when I supply a const char encString[] = "Hello, World!", but when I supply a raw string e.g. const char* a = charPtrDecrypt("Hello, World!", 14, true) It crashes.
There's an old saying (I know it's old, because I first posted it to Usenet around 1992 or so) that: "If you lie to the compiler, it will get its revenge." That's what's happening here.
Here:
const char* charPtrDecrypt(const char* encString, int len, bool encrypt)
...you promise that you will not modify the characters that encString points at. That's what the const says/means/does.
Here, however:
xtea::Encrypt(32, (uint32_t*)(encString + (i*BLOCK_SIZE)), key);
...you cast away that constness (cast to uint32_t *, with no const qualifier), and pass the pointer to a function that modifies the buffer it points at.
Then the compiler gets its revenge: it allows you to pass a pointer to data you can't modify, because you promise not to modify it--but then when you turn around and try to modify it anyway, your program crashes and burns because you try to modify read-only data.
This can be avoided in any number of ways. One would be to get away from the relatively low-level constructs you're using now, and pass/return std::strings instead of pointers to [const] char.
The code has still more problems than just that though. For one thing, it treats the input as a block of uint32_t items, and rounds its view of the length up to the next multiple of the size of a uint32_t (typically 4). Unfortunately, it doesn't actually change the size of the buffer, so even when the buffer is writable, it doesn't really work correctly--it still reads and writes beyond the end of the buffer.
Here again, std::string will be helpful: it lets us resize the string up to the correct size instead of just reading/writing past the end of the fixed-size buffer.
Along with that, there's a fact the compiler won't care about, but you (and any reader of this code) will (or at least should): the name of the function is misleading, and has parameters whose meaning isn't at all apparent--particularly the Boolean that governs whether to encrypt or decrypt. I'd advise using an enumeration instead, and renaming the function to something that can encompass either encryption or decryption:
Finally, I'd move the if statement that determines whether to encrypt or decrypt outside the loop, since we aren't going to change from one to the other as we process one input string.
Taking all those into account, we could end up with code something like this:
enum direction { ENCRYPT, DECRYPT };
std::string xtea_process(std::string enc_string, direction d) {
unsigned int key[4] = { 0xB5D1, 0x22BA, 0xC2BC, 0x9A4E };
size_t len = enc_string.size();
len += len % BLOCK_SIZE; // round up to next multiple of BLOCK_SIZE
enc_string.resize(len); // enlarge the string to that size, if necessary
if (direction == DECRYPT)
for (size_t i = 0; i < len; i+=BLOCK_SIZE)
xtea::Decrypt(32, reinterpret_cast<uint32_t *>(&encString[i]), key);
else
for (size_t i = 0; i < len; i += BLOCK_SIZE)
xtea::Encrypt(32, reinterpret_cast<uint32_t *>(&encString[i]), key);
}
return encString;
}
This does still leave (at least) one point that I haven't bothered to deal with: some machines may have stricter alignment requirements for a uint32_t than for char, and it's theoretically possible that the buffer used in a string won't meet those stricter alignment requirements. You could run into a situation where you need to copy the data out of the string, into a buffer that's properly aligned for uint32_t access, do the encryption/decryption, then copy the result back.
You pass a constant const char* to the function but cast it to a non-constant uint32_t*. I guess that xtea::Encrypt modifies the string buffer in place.
In the first version const char encString[] = "Hello, World!" the variable --while being const-- most likely lies on the stack which is modifiable. So it's "not nice" to remove the const, but it works.
In the second version you string most likely lies in a read-only data segment. So casting away const let's you call the Encrypt function, but crashes as soon as the function really tries to modify the string.
Related
I am trying to make a function like strcpy in C++. I cannot use built-in string.h functions because of restriction by our instructor. I have made the following function:
int strlen (char* string)
{
int len = 0;
while (string [len] != (char)0) len ++;
return len;
}
char* strcpy (char* *string1, char* string2)
{
for (int i = 0; i<strlen (string2); i++) *string1[i] = string2[i];
return *string1;
}
main()
{
char* i = "Farid";
strcpy (&i, "ABC ");
cout<<i;
}
But I am unable to set *string1 [i] value. When I try to do so an error appears on screen 'Program has encountered a problem and need to close'.
What should I do to resolve this problem?
Your strcpy function is wrong. When you write *string1[i] you are actually modifying the first character of the i-th element of an imaginary array of strings. That memory location does not exist and your program segfaults.
Do this instead:
char* strcpy (char* string1, char* string2)
{
for (int i = 0; i<strlen (string2); i++) string1[i] = string2[i];
return string1;
}
If you pass a char* the characters are already modifiable. Note It is responsibility of the caller to allocate the memory to hold the copy. And the declaration:
char* i = "Farid";
is not a valid allocation, because the i pointer will likely point to read-only memory. Do instead:
char i[100] = "Farid";
Now i holds 100 chars of local memory, plenty of room for your copy:
strcpy(i, "ABC ");
If you wanted this function to allocate memory, then you should create another one, say strdup():
char* strdup (char* string)
{
size_t len = strlen(string);
char *n = malloc(len);
if (!n)
return 0;
strcpy(n, string);
return n;
}
Now, with this function the caller has the responsibility to free the memory:
char *i = strdup("ABC ");
//use i
free(i);
Because this error in the declaration of strcpy: "char* *string1"
I don't think you meant string1 to be a pointer to a pointer to char.
Removing one of the * should word
The code has several issues:
You can't assign a string literal to char* because the string literal has type char const[N] (for a suitable value of N) which converts to char const* but not to char*. In C++03 it was possible to convert to char* for backward compatibility but this rule is now gone. That is, your i needs to be declared char const*. As implemented above, your code tries to write read-only memory which will have undesirable effects.
The declaration of std::strcpy() takes a char* and a char const*: for the first pointer you need to provide sufficient space to hold a string of the second argument. Since this is error-prone it is a bad idea to use strcpy() in the first place! Instead, you want to replicate std::strncpy() which takes as third argument the length of the first buffer (actually, I'm never sure if std::strncpy() guarantees zero termination or not; you definitely also want to guarantee zero termination).
It is a bad idea to use strlen() in the loop condition as the function needs to be evaluated for each iteration of the loop, effectively changing the complexity of strlen() from linear (O(N)) to quadratic (O(N2)). Quadratic complexity is very bad. Copying a string of 1000 characters takes 1000000 operations. If you want to try out the effect, copy a string with 1000000 characters using a linear and a quadratic algorithm.
Your strcpy() doesn't add a null-terminator.
In C++ (and in C since ~1990) the implicit int rule doesn't apply. That is, you really need to write int in front of main().
OK, a couple of things:
you are missing the return type for the main function
declaration. Not really allowed under the standard. Some compilers will still allow it, but others will fail on the compile.
the way you have your for loop structured in
strcpy you are calling your strlen function each time through
the loop, and it is having to re-count the characters in the source
string. Not a big deal with a string like "ABC " but as strings get
longer.... Better to save the value of the result into a variable and use that in the for loop
Because of the way that you are declaring i in
`main' you are pointing to read-only storage, and will be causing an
access violation
Look at the other answers here for how to rebuild your code.
Pointer use in C and C++ is a perennial issue. I'd like to suggest the following tutorial from Paul DiLorenzo, "Learning C++ Pointers for REAL dummies.".
(This is not to imply that you are a "dummy," it's just a reference to the ",insert subject here> for Dummies" lines of books. I would not be surprised that the insertion of "REAL" is to forestall lawsuits over trademarked titles)
It is an excellent tutorial.
Hope it helps.
I have been working with C++ strings and trying to load char * strings into std::string by using C functions such as strcpy(). Since strcpy() takes char * as a parameter, I have to cast it which goes something like this:
std::string destination;
unsigned char *source;
strcpy((char*)destination.c_str(), (char*)source);
The code works fine and when I run the program in a debugger, the value of *source is stored in destination, but for some odd reason it won't print out with the statement
std::cout << destination;
I noticed that if I use
std::cout << destination.c_str();
The value prints out correctly and all is well. Why does this happen? Is there a better method of copying an unsigned char* or char* into a std::string (stringstreams?) This seems to only happen when I specify the string as foo.c_str() in a copying operation.
Edit: To answer the question "why would you do this?", I am using strcpy() as a plain example. There are other times that it's more complex than assignment. For example, having to copy only X amount of string A into string B using strncpy() or passing a std::string to a function from a C library that takes a char * as a parameter for a buffer.
Here's what you want
std::string destination = source;
What you're doing is wrong on so many levels... you're writing over the inner representation of a std::string... I mean... not cool man... it's much more complex than that, arrays being resized, read-only memory... the works.
This is not a good idea at all for two reasons:
destination.c_str() is a const pointer and casting away it's const and writing to it is undefined behavior.
You haven't set the size of the string, meaning that it won't even necessealy have a large enough buffer to hold the string which is likely to cause an access violation.
std::string has a constructor which allows it to be constructed from a char* so simply write:
std::string destination = source
Well what you are doing is undefined behavior. Your c_str() returns a const char * and is not meant to be assigned to. Why not use the defined constructor or assignment operator.
std::string defines an implicit conversion from const char* to std::string... so use that.
You decided to cast away an error as c_str() returns a const char*, i.e., it does not allow for writing to its underlying buffer. You did everything you could to get around that and it didn't work (you shouldn't be surprised at this).
c_str() returns a const char* for good reason. You have no idea if this pointer points to the string's underlying buffer. You have no idea if this pointer points to a memory block large enough to hold your new string. The library is using its interface to tell you exactly how the return value of c_str() should be used and you're ignoring that completely.
Do not do what you are doing!!!
I repeat!
DO NOT DO WHAT YOU ARE DOING!!!
That it seems to sort of work when you do some weird things is a consequence of how the string class was implemented. You are almost certainly writing in memory you shouldn't be and a bunch of other bogus stuff.
When you need to interact with a C function that writes to a buffer there's two basic methods:
std::string read_from_sock(int sock) {
char buffer[1024] = "";
int recv = read(sock, buffer, 1024);
if (recv > 0) {
return std::string(buffer, buffer + recv);
}
return std::string();
}
Or you might try the peek method:
std::string read_from_sock(int sock) {
int recv = read(sock, 0, 0, MSG_PEEK);
if (recv > 0) {
std::vector<char> buf(recv);
recv = read(sock, &buf[0], recv, 0);
return std::string(buf.begin(), buf.end());
}
return std::string();
}
Of course, these are not very robust versions...but they illustrate the point.
First you should note that the value returned by c_str is a const char* and must not be modified. Actually it even does not have to point to the internal buffer of string.
In response to your edit:
having to copy only X amount of string A into string B using strncpy()
If string A is a char array, and string B is std::string, and strlen(A) >= X, then you can do this:
B.assign(A, A + X);
passing a std::string to a function from a C library that takes a char
* as a parameter for a buffer
If the parameter is actually const char *, you can use c_str() for that. But if it is just plain char *, and you are using a C++11 compliant compiler, then you can do the following:
c_function(&B[0]);
However, you need to ensure that there is room in the string for the data(same as if you were using a plain c-string), which you can do with a call to the resize() function. If the function writes an unspecified amount of characters to the string as a null-terminated c-string, then you will probably want to truncate the string afterward, like this:
B.resize(B.find('\0'));
The reason you can safely do this in a C++11 compiler and not a C++03 compiler is that in C++03, strings were not guaranteed by the standard to be contiguous, but in C++11, they are. If you want the guarantee in C++03, then you can use std::vector<char> instead.
I am trying to create a non-recursive method to swap a c-style string. It throws an exception in the Swap method. Could not figure out the problem.
void Swap(char *a, char* b)
{
char temp;
temp = *a;
*a = *b;
*b = temp;
}
void Reverse_String(char * str, int length)
{
for(int i=0 ; i <= length/2; i++) //do till the middle
{
Swap(str+i, str+length - i);
}
}
EDIT: I know there are fancier ways to do this. But since I'm learning, would like to know the problem with the code.
It throws an exception in the Swap method. Could not figure out the problem.
No it doesn't. Creating a temporary character and assigning characters can not possibly throw an exception. You might have an access violation, though, if your pointers don't point to blocks of memory you own.
The Reverse_String() function looks OK, assuming str points to at least length bytes of writable memory. There's not enough context in your question to extrapolate past that. I suspect you are passing invalid parameters. You'll need to show how you call Reverse_String() for us to determine if the call is valid or not.
If you are writing something like this:
char * str = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
Then you will definitely get an access violation, because str points to read-only memory. Try the following syntax instead:
char str[] = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
This will actually make a copy of the "Foo" string into a local buffer you can overwrite.
This answer refers to the comment by #user963018 made under #André Caron's answer (it's too long to be a comment).
char *str = "Foo";
The above declares a pointer to the first element of an array of char. The array is 4 characters long, 3 for F, o & o and 1 for a terminating NULL character. The array itself is stored in memory marked as read-only; which is why you were getting the access violation. In fact, in C++, your declaration is deprecated (it is allowed for backward compatibility to C) and your compiler should be warning you as such. If it isn't, try turning up the warning level. You should be using the following declaration:
const char *str = "Foo";
Now, the declaration indicates that str should not be used to modify whatever it is pointing to, and the compiler will complain if you attempt to do so.
char str[] = "Foo";
This declaration states that str is a array of 4 characters (including the NULL character). The difference here is that str is of type char[N] (where N == 4), not char *. However, str can decay to a pointer type if the context demands it, so you can pass it to the Swap function which expects a char *. Also, the memory containing Foo is no longer marked read-only, so you can modify it.
std::string str( "Foo" );
This declares an object of type std::string that contains the string "Foo". The memory that contains the string is dynamically allocated by the string object as required (some implementations may contain a small private buffer for small string optimization, but forget that for now). If you have string whose size may vary, or whose size you do not know at compile time, it is best to use std::string.
I have a situation in which I'm performing binary serialization of a some items and I'm writing them to an opaque byte buffer:
int SerializeToBuffer(unsigned char* buffer)
{
stringstream ss;
vector<Serializable> items = GetSerializables();
string serializedItem("");
short len = 0;
for(int i = 0; i < items.size(); ++i)
{
serializedItem = items[i].Serialize();
len = serializedItem.length();
// Write the bytes to the stream
ss.write(*(char*)&(len), 2);
ss.write(serializedItem.c_str(), len);
}
buffer = reinterpret_cast<unsigned char*>(
const_cast<char*>(ss.str().c_str()));
return items.size();
}
Is it safe to remove the const-ness from the ss.str().c_str() and then reinterpret_cast the result as unsigned char* then assign it to the buffer?
Note: the code is just to give you an idea of what I'm doing, it doesn't necessarily compile.
No removing const-ness of an inherently contant string will result in Undefined Behavior.
const char* c_str ( ) const;
Get C string equivalent
Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.
A terminating null character is automatically appended.
The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only guaranteed to remain unchanged until the next call to a non-constant member function of the string object.
Short answer: No
Long Answer: No. You really can't do that. The internal buffer of those object belong to the objects. Taking a reference to an internal structure is definitely a no-no and breaks encapsulation. Anyway those objects (with their internal buffer) will be destroyed at the end of the function and your buffer variable will point at uninitialized memory.
Use of const_cast<> is usually a sign that something in your design is wrong.
Use of reinterpret_cast<> usually means you are doing it wrong (or you are doing some very low level stuff).
You probably want to write something like this:
std::ostream& operator<<(std::ostream& stream, Data const& serializable)
{
return stream << serializable.internalData;
// Or if you want to write binary data to the file:
stream.write(static_cast<char*>(&serializable.internalData), sizeof(serializable.internalData);
return stream;
}
This is unsafe, partially because you're stripping off const, but more importantly because you're returning a pointer to an array that will be reclaimed when the function returns.
When you write
ss.str().c_str()
The return value of c_str() is only valid as long as the string object you invoked it on still exists. The signature of stringstream::str() is
string stringstream::str() const;
Which means that it returns a temporary string object. Consequently, as soon as the line
ss.str().c_str()
finishes executing, the temporary string object is reclaimed. This means that the outstanding pointer you received via c_str() is no longer valid, and any use of it leads to undefined behavior.
To fix this, if you really must return an unsigned char*, you'll need to manually copy the C-style string into its own buffer:
/* Get a copy of the string that won't be automatically destroyed at the end of a statement. */
string value = ss.str();
/* Extract the C-style string. */
const char* cStr = value.c_str();
/* Allocate a buffer and copy the contents of cStr into it. */
unsigned char* result = new unsigned char[value.length() + 1];
copy(cStr, cStr + value.length() + 1, result);
/* Hand back the result. */
return result;
Additionally, as #Als has pointed out, the stripping-off of const is a Bad Idea if you're planning on modifying the contents. If you aren't modifying the contents, it should be fine, but then you ought to be returning a const unsigned char* instead of an unsigned char*.
Hope this helps!
Since it appears that your primary consumer of this function is a C# application, making the signature more C#-friendly is a good start. Here's what I'd do if I were really crunched for time and didn't have time to do things "The Right Way" ;-]
using System::Runtime::InteropServices::OutAttribute;
void SerializeToBuffer([Out] array<unsigned char>^% buffer)
{
using System::Runtime::InteropServices::Marshal;
vector<Serializable> const& items = GetSerializables();
// or, if Serializable::Serialize() is non-const (which it shouldn't be)
//vector<Serializable> items = GetSerializables();
ostringstream ss(ios_base::binary);
for (size_t i = 0u; i != items.size(); ++i)
{
string const& serializedItem = items[i].Serialize();
unsigned short const len =
static_cast<unsigned short>(serializedItem.size());
ss.write(reinterpret_cast<char const*>(&len), sizeof(unsigned short));
ss.write(serializedItem.data(), len);
}
string const& s = ss.str();
buffer = gcnew array<unsigned char>(static_cast<int>(s.size()));
Marshal::Copy(
IntPtr(const_cast<char*>(s.data())),
buffer,
0,
buffer->Length
);
}
To C# code, this will have the signature:
void SerializeToBuffer(out byte[] buffer);
Here is the underlying problem:
buffer = ... ;
return items.size();
In the second-to last line you're assigning a new value to the local variable that used (up until that point) to hold the pointer your function was given as an argument. Then, immediately after, you return from the function, forgetting everything about the variable you just assigned to. That does not make sense!
What you probably want to do is to copy data from the memory pointed to by ss_str().c_str() to the memory pointed to by the pointer stored in buffer. Something like
memcpy(buffer, ss_str().s_str(), <an appropriate length here>)
Suppose that I have a unsigned char*, let's call it: some_data
unsigned char* some_data;
And some_data has url-like data in it. for example:
"aasdASDASsdfasdfasdf&Foo=cow&asdfasasdfadsfdsafasd"
I have a function that can grab the value of 'foo' as follows:
// looks for the value of 'foo'
bool grabFooValue(const std::string& p_string, std::string& p_foo_value)
{
size_t start = p_string.find("Foo="), end;
if(start == std::string::npos)
return false;
start += 4;
end = p_string.find_first_of("& ", start);
p_foo_value = p_string.substr(start, end - start);
return true;
}
The trouble is that I need a string to pass to this function, or at least a char* (which can be converted to a string no problem).
I can solve this problem by casting:
reinterpret_cast<char *>(some_data)
And then pass it to the function all okie-dokie
...
Until I used valgrind and found out that this can lead to a subtle memory leak.
Conditional jump or move depends on uninitialised value(s) __GI_strlen
From what I gathered, it has to do with the reinterpret casting messing up the null indicating the end of the string. Thus when c++ tries to figure out the length of the string thing's get screwy.
Given that I can't change the fact that some_data is represented by an unsigned char*, is there a way to go about using my grabFooValue function without having these subtle problems?
I'd prefer to keep the value-finding function that I already have, unless there is clearly a better way to rip the foo-value out of this (sometimes large) unsigned char*.
And despite the unsigned char* some_data 's varying, and sometimes large size, I can assume that the value of 'foo' will be somewhere early on, so my thoughts were to try and get a char* of the first X characters of the unsigned char*. This could potentially get rid of the string-length issue by having me set where the char* ends.
I tried using a combination of strncpy and casting but so far no dice. Any thoughts?
You need to know the length of the data your unsigned char * points to, since it isn't 0-terminated.
Then, use e.g:
std::string s((char *) some_data, (char *) some_data + len);