Passing const char* variables to a function - c++

I'm having a weird and unexpected result in my code and I'd like your support to explain me what happens here.
I have a structure of a confiration :
struct sConfig {
const char* ssid;
const char* password;
}
I'm loading this configuration using LittleFS from a deserialized json :
config.ssid = json["ssid"]; // so this is coming from the FS in a json file
config.password = json["password"]; // so this is coming from the FS in a json file
So far, all is fine, I can print out the value using
Serial.println(config.ssid);
I'm then calling an internal void function
startWiFi(config.ssid, config.password);
void startWiFi(const char* ssid, const char* psswd) {
Serial.println(ssid);
Serial.println(psswd);
}
As a result, the console returns :
⸮
and
?:⸮?#⸮8⸮?<9⸮?⸮8⸮?:⸮?#⸮8⸮?<9⸮?⸮8⸮?:⸮?#⸮8⸮?<9⸮?⸮8⸮?.:⸮?#⸮
What can be wrong in my variables ?
Please help me as I'm stuck.
Thanks a lot.

To fix the issue I'd avoid copying a pointer and copy the actual data.
So, instead of config.password = json["password"];
I'd declare ssid and password as char arrays and copy the values from the json with strncpy()
struct sConfig {
char ssid[32];
char password[64];
}
or I'd allocate them on the spot with a custom copy function
char * myCopy (char *destination, const char *source)
{
// I'm using 64 because is the max length of WPA2-PSK passwords
size_t len = strnlen(destination, 64);
destination = malloc((num + 1) * sizeof(char));
strncpy(destination, source, num);
return destination;
}
....
myCopy(config.ssid, json["ssid"]);
myCopy(config.password, json["password"]);

What's probably happening here is a use-after-free bug.
At config.ssid = json["ssid"] you copy a pointer to the internal memory of the json object. It's probably valid at the time of that copy (so the print succeeds), but when the json changes its state or gets deallocated, you get garbage at that memory address.
The solution is - as suggested in the other answer - copy the whole string and not just its address.

Related

How to initialize non-const member variables with const actual parameter?

When I initialize the constructor with the given data type of the parameter, I find that it goes wrong with the explaination that " const char* values cannot be assigned to char* entities".
class TString
{
private:
char* m_pData;
int m_nLength;
public:
TString();
TString(const char* pStr);
······
}
TString::TString(const char* pStr) {
this->m_pData = pStr;
}
What should I do to solve this problem? If possible, give me a right example.
Thanks in advance and apolpgize for my ignorance.
Const char * generally are prefined static compiled strings that cannot be changed because they are locked in the source code, or they come from some immutable source. This is in part, why they are marked const to prevent people from trying to change them.
The easiest solution to this problem is to take the const char * and make a copy of it on the heap, then it is no longer constant.
For example:
#include <string.h> // for strdup
...
TString::TString(const char* pStr) {
m_pData = strdup(pStr); // this will malloc and copy the string accepting const char * as input.
}
One thing you will need to consider, the m_pData is now on the heap, so in the destructor, you will want to free this data otherwise you will have a memory leak.
TString::~TString(){
free(m_pData);
}
You will also want in the TString() constructor to set the m_pData=NULL too.
This will work with strings, but if it's binary data i.e. no terminator allocate the data using malloc and use a memcpy, like:
m_pData=(char *)malloc(m_nlength*sizeof(char));
memcpy(m_pData,pStr,m_nlength);
Or some such.

SSLeay reading a PEM file

I am trying to use the PEM_read_bio function to get data from a file.
The version of SSLeay we are using is from 1997, so documentation is a bit thin on the ground. Thankfully in this case it seems there is a matching function documented here: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio.html
I originally tried this:
char ** names;
char ** headers;
unsigned char ** data;
long len;
BIO *in = BIO_new_file("C:\\filename.txt", "r");
if (!in)
{
// error
}
else
{
int result = PEM_read_bio(in, names, headers, data, &len);
}
BIO_free(in);
OPENSSL_free(names);
OPENSSL_free(headers);
OPENSSL_free(data);
However this results in a run-time check failure: The variable 'names' is being used without being initialized.
The documentation mentions OPENSSL_malloc( num ) is used to initialize memory, but it fails to mention whether it does this behind the scenes, or the user does it.
OPENSSL_malloc is similar in usage to C's malloc, but how are we supposed to know how much memory to allocate in advance, before reading the file?
I have tried the following at the beginning:
char ** names = reinterpret_cast<char **>(OPENSSL_malloc(2));
char ** headers = reinterpret_cast<char **>(OPENSSL_malloc(2));
unsigned char ** data = reinterpret_cast<unsigned char **>(OPENSSL_malloc(2));
long len;
This results in apparently random data.
The documentation you linked to says:
The name, header and data pointers are allocated via OPENSSL_malloc() and should be freed by the caller via OPENSSL_free() when no longer needed.
That means PEM_read_bio() calls OPENSSL_malloc() for you, and then you call OPENSSL_free() on the allocated memory it returns when you are doing with it.
You are passing uninitialized pointers to PEM_read_bio(), that is why it is failing. The name, header and data parameters are all output parameters. You need to pass in the addresses of your own pointer variables to receive the memory that PEM_read_bio() allocates for you, eg:
char *name;
char *headers;
unsigned char *data;
long len;
BIO *in = BIO_new_file("C:\\filename.txt", "r");
if (!in)
{
// error
}
else
{
int result = PEM_read_bio(in, &name, &headers, &data, &len);
if (!result)
{
// error
}
else
{
...
OPENSSL_free(name);
OPENSSL_free(headers);
OPENSSL_free(data);
}
BIO_free(in);
}

Read file content in SGX enclave

I'm trying to read the content of a file from an enclave using OCalls.
enclave.edl:
untrusted {
void ocall_print_string([in, string] const char *str);
void ocall_read_IMA_file([in, string] const char *filename, [out] char *buf, [out] int *size);
};
enclave.cpp:
void printf(const char *fmt, ...) {
ocall_print_string(fmt);
}
void read_IMA_file(const char *filename, char *buf, int *size) {
ocall_read_IMA_file(filename, buf, size);
printf(buf);
}
//whereas the read_IMA_file function is called with
char *buf;
int size;
read_IMA_file("test.txt", buf, &size);
implementation of ocall functions in the application:
void ocall_print_string(const char *str) {
printf("%s\n", str);
}
void ocall_read_IMA_file(const char *filename, char *content, int *size) {
content = (char*) malloc(sizeof(char) * 10);
memset(content, '\0', sizeof(char) *10);
char tmp[] = "1234567890";
copy(&tmp[0], &tmp[9], content);
cout << content << endl;
}
But the result I receive is the following:
123456789 (null)
I'm not sure what I'm doing wrong?
In the above program, the "read_IMA_file" trusted function is called with pointer variable(OUT pointer) of type character.Here we are passing the pointer variable without any memory allocation.
"read_IMA_file" initiate a OCall that allocate memory and do "Copy" operation.Now the allocated memory is valid within the untrusted region. So we are getting expected result for the "cout<
Since there is no trusted memory allocated for "content"(before calling Ocall), no copy back operation happens in "OUT" pointer during Ocall returns.
So "buf" doesn't contain any valid data while doing "print(buf)" after Ocall returns in trusted region.
Please try with valid OUT pointer to character buffer(with some memory allocation) or IN and OUT pointer to String buffer.
If you expect it to output 1234567890, then you may need to malloc(11) instead of malloc(10), plus the way you are using copy may contain a bug too.
copy(&tmp[0], &tmp[9], content);
is copying 123456789 to the content, it exclude the the last iterator &tmp[9] as I understand. For more detail, you may want to look at: http://www.cplusplus.com/reference/algorithm/copy/
Also, I think you are not reading in any content from file "test.txt" either.

const char *const changes because of a string (?)

Hello i am building a project and today after 500 lines of code i am going to shoot my self. Today i started a new class and some very strange things are happening:
class Target {
public:
Target(const int port);
virtual ~Target();
private:
const char* initialize_port(const int port) const;
const char *const port;
};
and cpp file:
Target::Target(const int port)
:
port(initialize_port(port))
{
cout<<this->port<<endl; //this cout 80
string test3="Target2";//when i replace with char * test3="Target2" then both couts in the constructor are working ok.
cout<<this->port<<endl; //this cout Target2!!!!!!
}
const char* Target::initialize_port(const int port) const {
string port_str = std::to_string(port);
const char* port_char=port_str.c_str();
return port_char; // OR/and when i replace with something like return "80" then both couts in the constructor are working ok.
}
Target::~Target() {
}
Like you can see in the cpp file, while the default constructor is being called it couts the "this->port", then i create a string, and then i print it again. How is it even possible to get a different response??
From netbeans:
80
Target2
RUN FINISHED; exit value 0; real time: 20ms; user: 0ms; system: 0ms
PS:When in the function initialize_port(const int port) i am giving a standard return, for example return "80"; everything is ok. When in the constructor i am replacing the string with char *, again everything is ok.
PS2:I know that i have some problems with my RAM. If someone will compile and there is no problem with the outputs (cout) please let me know.
Thanks in advance.
The problem comes from:
{
string port_str = std::to_string(port);
const char* port_char=port_str.c_str();
return port_char;
}
When the return happens, port_str is destroyed because it is a locale variable to that code block. Then port_char is a dangling pointer (a pointer that used to point to an object that has now been destroyed).
Using that pointer causes undefined behaviour and that explains your weird effects when you use the pointer.
To fix this, stop using raw pointers. The simplest fix is to use std::string instead.
The problem is that the return value of port_str.c_string() is only valid for the lifetime of port_str. Since that is allocated on the stack in initialize_port it becomes invalid once that function returns.
In your constructor, when you initialize the test3 string it ends up (mostly by chance) occupying the same memory as port_str did.
If you need to use a const char * you will need to allocate new memory for the string inside initialize_port (and deallocate it in your constructor!). Alternatively just stick with using std:string objects.

deal with void pointers and char in c++

i am working on a piece of code right now and got a problem with void pointer and char. basically, within the serialize function, we would have a new char. we would need to store that char in buffer. and here is the signature of serialize function.
void serialize(void *buffer,
//some other inputs here
){
std::string str = "";
/*some code here, store the final output in str first*/
char* charStr = new char[str.size()];
strcpy(charStr,str.c_str());
buffer = static_cast<void*>(charStr);
}
using the function like this,
char buffer[256];
serialize(buffer,
//some other inputs here
);
However, the data stored in buffer would be something real strange. I changed the void pointer in the signature to char pointer as a temporary solution. However, i know there must be a better one.
If you want to fill a buffer, you cannot assign to it (that will just overwrite the pointer, leaving the original buffer contents intact). You also do not need a temporary buffer in serialize (charStr). You can directly strcpy to the output buffer, like this:
void serialize(void *buffer
){
std::string str = "foo bar baz";
strcpy((char *)buffer, str.c_str());
}
define it as
void serialize(void *& buffer,
//some other inputs here
){
use pointer as parameter, remember to delete the buffer
char* buffer;
serialize(buffer,
//some other inputs here
);