Compiler Error: Invalid Conversion from int* to unsigned int* [-fpermissive] - c++

I'm having the strangest issue today. I was working with an example online, and to my lack of surprise, it didn't work (they pretty much never do). I went about fixing it myself, but I seem to be stuck on this error:
Error: Invalid Conversion from int* to unsigned int* [-fpermissive]
I understand this. I'm providing an int*, it wants an unsigned int*. However, I don't actually know why the int* is being generated.
Here's the snippet code throwing the problem:
unsigned char md_value[EVP_MAX_MD_SIZE];
int md_length;
EVP_DigestFinal_ex(md_ctx, md_value, &md_length);
The third argument of that function call, &md_length, is causing the problem. Looking at the documentation for that function call (From OpenSSL, if it
matters), it expects the argument to be of unsigned int* type, which makes since, because it wants an address (or at least that how the example I'm working with is using it).
Funny thing is, I thought that the & operator returned an unsigned int*, as returning an int* doesn't make sense, seeing as computers don't have negative addresses in their memory.
Here's the example I'm following along with, if you wish to take a look: https://www.openssl.org/docs/crypto/EVP_DigestInit.html
Below is the Source Code, should you want to try it out yourself. I doubt you'll actually need to read it to solve this problem, but having it here couldn't hurt.
Source Code:
//* Description *//
// Title: Example
// Author: Boom Blockhead
// Example Program to Test OpenSSL
//* Libraries *//
#include <stdio.h>
#include <cstring>
#include <openssl/evp.h>
//* Namespaces *//
using namespace std;
//* Main Method *//
// Runs the Program and Interprets the Command Line
int main(int argc, char* argv[])
{
// Initialize the Messages
char msg1[] = "Test Message\n";
char msg2[] = "Hello World\n";
// Validate Argument Count
if(argc != 2)
{
printf("Usage: %s digestname\n", argv[0]);
exit(1);
}
// Determine Message Digest by Name
OpenSSL_add_all_digests();
const EVP_MD* md = EVP_get_digestbyname(argv[1]);
// Make sure a Message Digest Type was Found
if(md == 0)
{
printf("Unknown Message Digest %s\n", argv[1]);
exit(1);
}
// Create the Message Digest Context
EVP_MD_CTX* md_ctx = EVP_MD_CTX_create();
// Setup the Message Digest Type
EVP_DigestInit_ex(md_ctx, md, NULL);
// Add the Messages to be Digested
EVP_DigestUpdate(md_ctx, msg1, strlen(msg1));
EVP_DigestUpdate(md_ctx, msg2, strlen(msg2));
// Digest the Message
unsigned char md_value[EVP_MAX_MD_SIZE];
int md_length;
EVP_DigestFinal_ex(md_ctx, md_value, &md_length); // <--- ERROR
// Destroy the Message Digest Context
EVP_MD_CTX_destroy(md_ctx);
// Print the Digested Text
printf("Digest is: ");
for(int i = 0; i < md_length; i++)
printf("%02x", md_value[i]);
printf("\n");
// Clean up the Message Digest
EVP_cleanup();
// Exit the Program
exit(0);
return 0;
}
Also, putting the explicit cast of (unsigned int*) seems to just make things worse, as I then get the follow error:
example.cpp:(.text+0x91): undefined reference to `OpenSSl_add_all_digests`
...
example.cpp:(.text+0x1ec): undefined reference to `EVP_cleanup`
Basically, it complains about all of the OpenSSL functions.
Lastly, (again, this is just to give you guys everything you could possibly need) I'm not sending in any funny arguments to the compiler. I'm just using:
gcc example.cpp -o example.out
Since there's an error, the example.out never actually gets created.

Funny thing is, I thought that the & operator returned an unsigned int*, as returning an int* doesn't make sense, seeing as computers don't have negative addresses in their memory.
That's not "funny"; it's just wrong.
The address-of operator applied to an object of type T gives you a pointer of type T*.
Period.
Whether T is an unsigned or signed type doesn't come into it, and has nothing to do with philosophical debate involved about whether computers may have negative addresses. In fact, pointers are generally signed because, if they weren't, you'd soon get stuck when you try to take the difference between two addresses, or walk backwards in the address space.
But that has nothing to do with the use of the term unsigned in your code.

as returning an int* doesn't make sense, seeing as computers don't have negative addresses in their memory.
You are misunderstanding what the type name means.
unsigned int* is a pointer to an unsigned int. unsigned does not refer to the pointer value.
So the solution is to change your int to unsigned int.

Funny thing is, I thought that the & operator returned an unsigned int*, as returning an int* doesn't make sense, seeing as computers don't have negative addresses in their memory
It's not the signed-ness of the memory address number (the pointer's underlying value), it's the signed-ness of the datatype stored within the memory addresses, in this case integers.
Change your md_length to an unsigned int as per the spec and it should be OK.

Related

Why does a `char *` allocated through malloc prints out gibberish after the function allocating it returns?

I'm trying to write a function to parse and extract the components of a URL. Moreover, I need the components (e.g. hostname) to have the type char * since I intend to pass them to C APIs.
My current approach is to save the components in the parse_url function to the heap by calling malloc. But for some reason, the following code is printing gibberish. I'm confused by this behavior because I thought memory allocated on the heap will persist even after the function allocating it returns.
I'm new to C/C++, so please let me know what I did wrong and how to achieve what I wanted. Thank you.
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
void cast_to_cstyle(string source, char *target)
{
target = (char *)malloc(source.size() + 1);
memcpy(target, source.c_str(), source.size() + 1);
}
void parse_url(string url, char *protocol_cstyle, char *hostname_cstyle, char *port_cstyle, char *path_cstyle)
{
size_t found = url.find_first_of(":");
string protocol = url.substr(0, found);
string url_new = url.substr(found + 3); // `url_new` is the url excluding the "http//" part
size_t found1 = url_new.find_first_of(":");
string hostname = url_new.substr(0, found1);
size_t found2 = url_new.find_first_of("/");
string port = url_new.substr(found1 + 1, found2 - found1 - 1);
string path = url_new.substr(found2);
cast_to_cstyle(protocol, protocol_cstyle);
cast_to_cstyle(hostname, hostname_cstyle);
cast_to_cstyle(port, port_cstyle);
cast_to_cstyle(path, path_cstyle);
}
int main() {
char *protocol;
char *hostname;
char *port;
char *path;
parse_url("http://www.example.com:80/file.txt", protocol, hostname, port, path);
printf("%s, %s, %s, %s\n", (protocol), (hostname), (port), (path));
return 0;
}
The problem is that arguments are passed by value, so the newly created string never leaves the function (albeit exists until program termination as free is never called on it). You can pass by reference¹ like:
void cast_to_cstyle(string source, char *&target)
or better, pass the source string by (constant) reference too (string is expensive to copy):
void cast_to_cstyle(const string &source, char *&target)
(neither function body nor the call site need to be changed).
But you may not need even that.
If the API doesn’t actually modify the string despite using non-const pointer (pretty common in C AFAIK), you can use const_cast, like const_cast<char *>(source.c_str()).
Even if it may modify the string, &source[0] is suitable (at least since C++11). It may not seem right but it is:
a pointer to s[0] can be passed to functions that expect a pointer to the first element of a null-terminated (since C++11)CharT[] array.
— https://en.cppreference.com/w/cpp/string/basic_string
(and since C++17 data() is the way to go).
However, unlike that obtained from malloc any such pointer becomes invalid when the string is resized or destroyed (be careful “the string” means “that particular copy of the string” if you have several).
¹ Strictly speaking, pass a reference; references aren’t restricted to function arguments in C++.
The problem was as #WeatherVane and #JerryJeremiah mentioned. The pointer returned by malloc and assigned to target was in the local scope of cast_to_cstyle(), which got destroyed after the function returns. So the protocol, hostname, port, path variables declared in main were never assigned, hence it printed out gibberish. I've fixed this by making the cast_to_style() returns a char *.
char *cast_to_cstyle_str(string source)
{
char *target = (char *)malloc(source.size() + 1);
memcpy(target, source.c_str(), source.size() + 1);
return target;
}
Note: I forgot to free up malloc in my question.

Why does this segmentation fault?

I was trying to make a factorial program that takes input from the terminal but it doesn't work..
giving it anything but no arguments gives a segmentation fault
// factorial calculator
#include <iostream>
using namespace std;
long factorial(long a) {
if (a > 1)
return (a * factorial(a-1));
else
return 1;
}
int main(int argc, char *argv[]) {
long number = (long) argv[1];
cout << number << "! = " << factorial(number) << '\n';
return 0;
}
also for some reason number has the value of 140732199978159 when I do ./factorial 2
(all I got from attempting to find an answer by searching was that a segfault means that I'm accessing something I'm not supposed to. I don't understand where I've done that here.)
long number = (long) argv[1];
This takes argv[1] and casts it to long. argv is a char*[] (for simplicity, I'll assume it's the very similar type char** for this explanation). Hence, argv[1] is a char*. Casting a char* to long takes its address as a numerical value. That's a position in memory on your computer and not helpful for calculating the factorial.
Consider strtol, a built-in C++ function that does exactly what you want.
long number = std::strtol(argv[1], nullptr, 10);
10 is the numerical base (we do our math in base 10, generally). The second argument is optional and not necessary for our use case, so we pass nullptr since we don't need it.
(long) argv[1];
argv[1] is a const char *, a pointer to some unspecified number of characters.
Even if that character string happens to be "2", converting the pointer to a long value, like this, does not get you an actual number 2. That's not how C++ works. All this does is reinterpret the raw memory address, that the pointer is pointing to. You get, pretty much, a junk number, and attempting to compute its factorial results in equally meaningless results.
You'll need to use some suitable library function, like atol from the C library, or std::stol from the C++ library (with some overhead due to a temporary conversion to a std::string) in order to get the expected results.

How to pass on 'char* data' when the data is stored as vector of uint8_t?

I have a class defined like this:
class sco
{
private:
public:
vector<uint8_t> data;
sco(vector<uint8_t> data);
~sco();
};
Where the constructor is:
sco::sco(vector<uint8_t> data) {
this->data = data;
}
I then have a function which is declared like this:
void send(unsigned& id, char* data, char len);
My problem is that I need to pass the data of a sco member to it, but the difference of type and the pointer is confusing me. If I have a member newSco with some data in it, would it be reasonable to call this send function as send(someId, (char*)&(newSco.data.begin()), newSco.data.size() ); ? Please note, that the function send is for a microcontroller, and it takes in char type so I can't change that, and neither can I change uint8_t as that is the type which is coming in from a serial communication. I have wasted over 3 days trying to convert types to something mutual, just to reverse it back because it destroyed everything. I give up and I will no longer try to manipulate the types, as I just do not have that sort of time and just need it to work even if it is bad practice. I thought uint8_t and char are of the same size, so it shouldn't matter.
send(someId, (char*)&(newSco.data.begin()), newSco.data.size() )
You almost had it with this, but not quite.
Here's why:
begin() gives you an iterator. You're taking the address of that iterator, so you're a level of indirection off. Using a C-style cast has masked what would otherwise be a type-related compilation error.
We could write (char*)&*(newSco.data.begin()) instead to dereference the iterator then take the address of the resulting first element.
But if the container were empty, this is very broken. You can't dereference a thing that doesn't exist.
So now we try:
send(someId, (char*)&newSco.data[0], newSco.data.size() )
Unfortunately this is also not safe if the container is empty, since .data[0] also effectively dereferences an element that may not exist. Some argue that the implied &* "cancels it out", but that's controversial and I've never believed it.
If you ever move to C++11 or later, you can use the perfectly safe:
send(someId, (char*)newSco.data.data(), newSco.data.size() )
Otherwise, stick with &newSco.data[0] but skip the entire send call when newSco.data.size() is zero. Can't emphasise that enough.
The cast to char* is itself safe; you can freely interpret uint8_ts as chars in this manner; there's a special rule for it. I've used this pattern myself a few times.
But, as above, a C-style cast is less than ideal. Prefer a nice reinterpret. I'd also add some const for good measure (skip this if your MC's API doesn't permit it):
if (!newSco.data.empty())
{
send(
someId,
reinterpret_cast<const char*>(&newSco.data[0]),
newSco.data.size()
);
}
There. Gorgeous. 😊
As a final note, since the API takes a char for the final parameter, I'd consider putting an upper bound on the container size. You can run the function in a loop, sending either CHAR_MAX or newSco.data.size() bytes at a time (whichever is smaller). Otherwise, if you expect more than CHAR_MAX elements in the container, you're going to get a nasty overflow!
This should work:
send(someId, static_cast<char*>(&newSco.data[0]), static_cast<char>(newSco.data.size()));
Additional Info:
How to convert vector to array
What is the difference between static_cast<> and C style casting?
Yes it is reasonable to cast the pointer to char* in this case. In general, you may not refer to the same memory location with different typed pointers due to strict aliasing rules. However, 'char' is a special case so the cast is allowed.
You shouldn't cast uint32_t* to int32_t though, for example, even though it may work in some cases.
Edit: As the comments below noted: casting from uint8_t* to char* may be fine, casting from iterator is not. use .data() instead of .begin().
If you can use at least C++11, the std::vector class provides data() which returns the raw array.If you are before C++11, I'm afraid you have to iterate over the vector and manually build your char*.
But, you cannot static_cast an unsigned char* to a char*. It is not allowed.But you are lucky, char* is an exception that does not break the strict aliasing rule. So you can use reinterpret_cast instead.
So you may solve your problem as follows:
Before C++11:
std::vector<uint8_t> a; // For the example
a.push_back('a');
a.push_back('b');
a.push_back('c');
a.push_back('d');
char b[a.size()];
for(unsigned int i = 0; i < a.size(); ++i)
{
b[i] = static_cast<char>(a[i]);
}
After C++11:
std::vector<uint8_t> a {'a', 'b', 'c', 'd'}; //uint8_t aka unsigned char
char * b = reinterpret_cast<char*>(a.data()); // b is a char* so the reinterpret_cast is safe
I hope it can help.
try to use reinterpret_cast.
Example:
#include <iostream>
#include <unistd.h>
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<uint8_t> v{65,66,67,68,69,70};
char* ptr = reinterpret_cast<char*>(v.data());
for (auto i{0}; i < v.size(); i++) {
std::cout << *ptr++ << std::endl;
}
return 0;
}
for your case:
void send(someId, reinterpret_cast<char*>(sco.data.data()), sco.data.size());

Convert Address to long - variable results in value?

Can anybody explain this behaviour to me pls?
static short nDoSomething(const char* pcMsg, ...)
{
va_list pvArgument;
long lTest;
void* pvTest = NULL;
va_start(pvArgument, pcMsg);
pvTest = va_arg(pvArgument, void*);
lTest = (long) pvTest;
va_end(pvArgument);
return 0;
}
If I call this function in the main like this:
int main(int argc, char* argv[])
{
char acTest1[20];
nDoSomething("TestMessage", 1234567L, acTest1);
return 0;
}
I thought that the address of pvTest would be in lTest, but in fact it contains 1234567 ...
How is this possible?
Your code contains undefined behavior; the standard requires
that the type extracted using va_arg correspond to the type
passed (modulo cv-qualifiers, perhaps): You passed a long, and
read a void*, so anything which the compiler does is correct.
In practice, most compilers generate code which does no type
checking. If on your machine, long and void* have the same
size (and the machine has linear addressing), you will probably
end up with whatever you passed as long. If the sizes of the
two are different, but the machine is little endian, and you
pass a small enough value, you might end up with the same value
as well. But this is not at all guaranteed.
You are just lucky here.
va_start(pvArgument, pcMsg);
prepares for va_arg(pvArgument,T) to extract the next variable
argument following pcMsg with the presumption that it is of type T.
The next argument after pcMsg is in fact the long int 1234567; but
you wrongly extract it as a void * and then cast it to long into
lTest. You are just lucky that a void * on your system is the
same size as a long.
(Or maybe I mean oddly unlucky)

Why do they want an 'unsigned char*' and not just a normal string or 'char*'

EDIT: After taking adivce I have rearranged the parameters & types. But the application crashes when I call the digest() function now? Any ideas whats going wrong?
const std::string message = "to be encrypted";
unsigned char* hashMessage;
SHA256::getInstance()->digest( message, hashMessage ); // crash occurs here, what am I doing wrong?
printf("AFTER: n"); //, hashMessage); // line never reached
I am using an open source implementation of the SHA256 algorithm in C++. My problem is understanding how to pass a unsigned char* version of my string so it can be hashed?
This is the function that takes a unsigned char* version of my string:
void SHA256::digest(const std::string &buf, unsigned char *dig) {
init();
update(reinterpret_cast<const unsigned char *>(buf.c_str()), static_cast<unsigned int>(buf.length()));
final();
digest(dig);
}
How can I convert my string(which I want hashed) to an unsigned char*?
The following code I have made causes a runtime error when I go to print out the string contents:
const std::string hashOutput;
char message[] = "to be encrypted";
printf("BEFORE: %s bb\n", hashOutput.c_str());
SHA256::getInstance()->digest( hashOutput, reinterpret_cast<unsigned char *>(message) );
printf("AFTER: %s\n", hashOutput.c_str()); // CRASH occurs here
PS: I have been looking at many implementations of SHA256 & they all take an unsigned char* as the message to be hashed. Why do they do that? Why not a char* or a string instead?
You have the parameters around the wrong way. Buf is the input (data to be hashed) and dig is the output digest ( the hash).
Furthermore, a hash is binary data. You will have to convert said binary data into some string representation prior to printing it to screen. Normally, people choose to use a hexadecimal string for this.
The reason that unsigned char is used is that it has guaranteed behaviours under bitwise operations, shifts, and overflow.
char, (when it corresponds to signed char) does not give any of these guarantees, and so is far less useable for operations intended to act directly on the underlying bits in a string.
The answer to the question: "why does it crash?" is "you got lucky!". Your code has undefined behaviour. In short, you are writing through a pointer hashMessage that has never been initialised to point to any memory. A short investigation of the source code for the library that you are using reveals that it requires the digest pointer to point to a block of valid memory that is at least SHA256_DIGEST_SIZE chars long.
To fix this problem, all that you need to do is to make sure that the pointer that you pass in as the digest argument (hashMessage) is properly initialised, and points to a block of memory of sufficient size. In code:
const std::string message("to be encrypted");
unsigned char hashMessage[SHA256_DIGEST_SIZE];
SHA256::getInstance()->digest( message, hashMessage );
//hashMessage should now contain the hash of message.
I don't know how a SHA256 hash is produced but maybe it involves some sort of arithmetic that needs to be done on a unsigned data type.
Why does it matter? Get a char* from your string object by calling the c_str() method then cast to unsigned char*.