free heap esp32, string-formatter - c++

I'm using the function storePrintf for string formatting (googled it) - it works fine, but on 3d or 4th day I see the next error:
[E][ssl_client.cpp:33] _handle_error(): [start_ssl_client():199]: (-17040) RSA - The public key operation failed : BIGNUM - Memory allocation failed
simplified code shows the order of functions calls
void setup() {
Serial.begin(115200);
}
char *buf ;
char *storePrintf(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
size_t sz = snprintf(NULL, 0, fmt, arg);
buf = (char *)malloc(sz + 1);
vsprintf(buf, fmt, arg);
va_end(arg);
return buf;
}
void loop() {
String s = storePrintf("==========================: ml = %.2f, val = %d\n", 0.12, 2);
Serial.println("s = " + s);
free(buf);
delay(2000);
}
// this works well, but if code has a lot of calls to storePrintf with free(buf) gets error
I suppose that Memory allocation failed due to the never call free(buf); after allocation memory for buf.
when I try to call free(buf); directly after calling storePrintf(..) in some moment appears another error:
CORRUPT HEAP: Bad tail at 0x3ffdb993. Expected 0xbaad5678 got 0xbaad5600 assertion "head != NULL" failed
Help please to fix this issue,

Related

Passing const char* into constructor gives null

I'm trying to make a simple logger to log to a file to give me debug information about my program. I want to avoid using a library so I'm making one myself.
logging.cpp
#include <string.h> // String stuff
#include <time.h> // Time
#include "logging.hpp"
// Cathooks main logging util
CatLogger g_CatLogging("/tmp/nekohook.log");
//CatLogger g_CatLogging;
CatLogger::CatLogger(const char* _file_path, bool _ptime) : ptime(_ptime) {
file_path = _file_path;
}
CatLogger::~CatLogger() { fclose(log_handle); }
void CatLogger::log(const char* fmt, ...) {
// Basicly an init, because this cant be done on construct
if (log_handle == nullptr) {
log_handle = fopen(file_path, "w");
}
// Print our time if needed
if (ptime) {
// Get our time
time_t current_time = time(0);
struct tm* time_info = localtime(&current_time);
// print it to a string
char timeString[10];
strftime(timeString, sizeof(timeString), "%H:%M:%S", time_info);
// Print the time into the log
fprintf(log_handle, "%% [%s] ", timeString);
}
// Get the string we want to log
char buffer[1024];
va_list list;
va_start(list, fmt);
vsprintf(buffer, fmt, list);
va_end(list);
// Write our log to the file
fprintf(log_handle, "%s\n", file_path, buffer);
fflush(log_handle);
// Push result var to a console here, if i ever make a console api
}
logging.hpp
#include <stdarg.h> // ... arg
#include <stdio.h> // fopen(), fprint(), fputs()
class CatLogger {
public:
CatLogger(const char* _file_path, bool _ptime = false);
~CatLogger();
void log(const char* fmt, ...); // Use to log with
private:
FILE* log_handle = 0; // Handle used to log to files with
const char* file_path; // Path to log file
const bool ptime; // Whether to print time
};
// Use this to log
extern CatLogger g_CatLogging;
When I use the log function, it fails. I have no idea why. I made a dummy function that crashes when ran to get info from gdb of the input. I input the file_path variable into it and it returns 0x0. I'm not sure why this happens, I've made a sample executable separate from the library I'm using this in and it works flawlessly. Could this be due to the way I'm linking libraries or the lack of?
Here is the library I am working on with a link directly to the logging file.
https://github.com/oneechanhax/nekohook/blob/master/src/util/logging.cpp
It crashes on fprintf() on both due to fopen not returning a file handle, which is in turn because const char* isn't being passes for some reason.
Please tell me a way to debug this or point out where this went wrong as I'm at a loss trying for myself.
EDIT:
If i replace the following in CatLogger::log
if (log_handle == nullptr) {
log_handle = fopen(file_path, "w");
}
With the following
if (log_handle == nullptr) {
log_handle = fopen("/tmp/nekohook.log", "w");
}
It now works but i cant change the log location for other log classes now...
EDIT2:
Here is some debug info. Somehow the const char* doesnt get saved into the class. Thats the main issue that i have...
example
Maybe the string becomes null after constructing...
There are a lot of potential bugs.
if (log_handle == nullptr) {
log_handle = fopen(file_path, "w");
if(!log_handle) {
perror("File opening failed"); // check your console output.
return EXIT_FAILURE;
}
}
// Get the string we want to log
char buffer[1024];
va_list list;
va_start(list, fmt);
vsprintf(buffer, fmt, list); // potential segmentation fault
va_end(list);
use this instead
int vsnprintf( char* buffer, std::size_t buf_size, const char* format, va_list vlist ); // (since C++11)
And more it the program is multithreaded.
This was a case of static init order fiasco where the const char* wouldn't get initialized before the function was called.
The solution was to make the file link first compared to other files and the object works now.

Reuse SuperpoweredDecoder for loading audio files

For benchmarking purposes I repeat loading an .wav-file, processing it offline and saving the output by using the SuperpoweredSDK.
But after some iterations (in my case 4) I get the error "A/libc: invalid address or address of corrupt block 0x5e825000 passed to dlfree" when I try to release the shortIntBuffer.
extern "C" JNIEXPORT void JNICALL
Java_com_example_sebas_superpoweredtest_MainActivity_testDecoderReuse(JNIEnv *env, jobject instance,
jstring apkPath_,
jlong fileOffset,
jlong fileLength,
jstring outputFileName_) {
const char *apkPath = env->GetStringUTFChars(apkPath_, 0);
const char *outputFileName = env->GetStringUTFChars(outputFileName_, 0);
SuperpoweredDecoder decoder;
short int* shortIntBuffer;
FILE* fd;
for(int i = 0; i < 100; ++i) {
__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "RUN %d", i+1);
//open InputFile
const char *openError = decoder.open(apkPath, false, fileOffset, fileLength);
if (openError) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", openError);
return;
};
shortIntBuffer = new short int[decoder.samplesPerFrame * 4 + 16384] {0};
fd = createWAV(outputFileName, decoder.samplerate, 2);
if (!fd) {
__android_log_print(ANDROID_LOG_ERROR,LOG_TAG, "Failed creating File %s", outputFileName);
return;
};
//process samples
unsigned int samplesDecoded;
while (true) {
// Decode one frame. samplesDecoded will be overwritten with the actual decoded number of samples.
samplesDecoded = decoder.samplesPerFrame;
if (decoder.decode(shortIntBuffer, &samplesDecoded) == SUPERPOWEREDDECODER_ERROR) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Error while decoding samples.");
break;
}
if (samplesDecoded < 1) break;
// Write the audio to disk.
fwrite(shortIntBuffer, 1, samplesDecoded * 4, fd);
};
//close resources
if(fd) {
closeWAV(fd);
__android_log_print(ANDROID_LOG_ERROR,LOG_TAG, "Closed wav.");
}
delete[](shortIntBuffer); // <- SIGSEGV (signal SIGSEGV: invalid address (fault address: 0xdeadbaad))
__android_log_print(ANDROID_LOG_ERROR,LOG_TAG, "Deleted shortInBuffer");
}
env->ReleaseStringUTFChars(apkPath_, apkPath);
env->ReleaseStringUTFChars(outputFileName_, outputFileName);
}
I don't understand why the code works fine for the first iterations but not for all iterations. I would be grateful to hear from you to solve this problem.
Thanks in advance
This is the LLDB-Frame when I get the message: "Fatal signal 11 (SIGSEGV) at 0xfde0fdec (code=1), thread 9779 (uperpoweredtest)"

How to avoid SIGABRT when generating RSA Signature at EVP_SignFinal

I'm trying to generate a RSA Signature with libopenssl for c++:
But when I run my code, I get a SIGABRT. I did some deep debugging into libopenssl internal stuff to see where the Segfault comes from. I'll come to this later on.
First I want to make clear, that the RSA PrivateKey was successfully loaded from a .pem file. So Im pretty sure that's not the problem's origin.
So my question is: How to avoid the SIGABRT and what is the cause of it ?
I'm doing this for my B.Sc. Thesis so I really appreciate your help :)
Signature Generation Function:
DocumentSignature* RSASignatureGenerator::generateSignature(ContentHash* ch, CryptographicKey* pK) throw(PDVSException) {
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
if(pK == nullptr)
throw MissingPrivateKeyException();
if(pK->getKeyType() != CryptographicKey::KeyType::RSA_PRIVATE || !dynamic_cast<RSAPrivateKey*>(pK))
throw KeyTypeMissmatchException(pK->getPem()->getPath().string(), "Generate RSA Signature");
//get msg to encrypt
const char* msg = ch->getStringHash().c_str();
//get openssl rsa key
RSA* rsaPK = dynamic_cast<RSAPrivateKey*>(pK)->createOpenSSLRSAKeyObject();
//create openssl signing context
EVP_MD_CTX* rsaSignCtx = EVP_MD_CTX_create();
EVP_PKEY* priKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(priKey, rsaPK);
//init ctxt
if (EVP_SignInit(rsaSignCtx, EVP_sha256()) <=0)
throw RSASignatureGenerationException();
//add data to sign
if (EVP_SignUpdate(rsaSignCtx, msg, std::strlen(msg)) <= 0) {
throw RSASignatureGenerationException();
}
//create result byte signature struct
DocumentSignature::ByteSignature* byteSig = new DocumentSignature::ByteSignature();
//set size to max possible
byteSig->size = EVP_MAX_MD_SIZE;
//alloc buffer memory
byteSig->data = (unsigned char*)malloc(byteSig->size);
//do signing
if (EVP_SignFinal(rsaSignCtx, byteSig->data, (unsigned int*) &byteSig->size, priKey) <= 0)
throw RSASignatureGenerationException();
DocumentSignature* res = new DocumentSignature(ch);
res->setByteSignature(byteSig);
EVP_MD_CTX_destroy(rsaSignCtx);
//TODO open SSL Memory leaks -> where to free open ssl stuff?!
return res;
}
RSA* rsaPK = dynamic_cast(pK)->createOpenSSLRSAKeyObject();
virtual RSA* createOpenSSLRSAKeyObject() throw (PDVSException) override {
RSA* rsa = NULL;
const char* c_string = _pem->getContent().c_str();
BIO * keybio = BIO_new_mem_buf((void*)c_string, -1);
if (keybio==NULL)
throw OpenSSLRSAPrivateKeyObjectCreationException(_pem->getPath());
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
if(rsa == nullptr)
throw OpenSSLRSAPrivateKeyObjectCreationException(_pem->getPath());
//BIO_free(keybio);
return rsa;
}
SigAbrt origin in file openssl/crypto/mem.c
void CRYPTO_free(void *str, const char *file, int line)
{
if (free_impl != NULL && free_impl != &CRYPTO_free) {
free_impl(str, file, line);
return;
}
#ifndef OPENSSL_NO_CRYPTO_MDEBUG
if (call_malloc_debug) {
CRYPTO_mem_debug_free(str, 0, file, line);
free(str);
CRYPTO_mem_debug_free(str, 1, file, line);
} else {
free(str);
}
#else
free(str); // <<<<<<< HERE
#endif
}
the stacktrace
stacktrace screenshot from debugger (clion - gdb based)
I just found the Bug (and Im really not sure if this is a libopenssl bug..)
//set size to max possible
byteSig->size = EVP_MAX_MD_SIZE;
//alloc buffer memory
byteSig->data = (unsigned char*)malloc(byteSig->size);
The problem was when I set the buffer size to EVP_MAX_MD_SIZE!
The (in my opinion) very very strange thing is, that you have to keep the size uninitialized! (not even set to 0 - just "size_t size;" ).
Strange thing here is that then you also HAVE TO allocate memory just like I did. I dont understand this because then an undefined size of memory gets allocated..
What the really weird is that libopenssl internally sets the size back to 0 and allocates the memory itself.. (I detected this by browsing the libopenssl source code)

malloc and snprintf bus core dump

Function which worked previously, suddenly refuses cooperation. More precisely this snippet:
//If not, add to UIDS
printf("line 78\n");
free(s2);
printf("line 82\n");
char * ss = malloc(snprintf(NULL, 0, "%s:%d", myUIDs, userId) + 1);
printf("line 84\n");
sprintf(ss, "%s:%d", myUIDs, userId);
free(myUIDs);
myUIDs=ss;
free(buffer);
Program fails one line after "line 82" (no longer line 82, but it's only a debugging stop) with Segmentation Fault (core dumped).
If I change
char * ss = malloc(snprintf(NULL, 0, "%s:%d", myUIDs, userId) + 1); to
char * ss = malloc(snprintf(NULL, 0, "%s:%d", "", 1) + 1);
I get Bus Error: Code dumped instead. I'm working on this program for quite a long time, and I have a feeling it's something obvious, that I'm constantly overlooking because of exhaustion, but no programmer friends to ask for help at this time.
Whole function for context:
char* myUIDs; //string containing all UID-s, separated by colon
void printProcessInformation(char pid[],int isSetP, int isSetN, int isSetU){
//find full path name to your "stat" file
//DIR *dir;
//struct dirent *ent;
//Creating string with /proc/PID
char * s = malloc(snprintf(NULL, 0, "%s%s", "/proc/", pid) + 1);
sprintf(s, "%s%s", "/proc/", pid);
//Creating string with /proc/PID/psinfo (full path)
char * fullPath = malloc(snprintf(NULL, 0, "%s%s", s, "/psinfo") + 1);
sprintf(fullPath, "%s%s", s, "/psinfo");
free(s);
//printf("%s\n",fullPath);
//Reading data from file
FILE* file = fopen(fullPath, "r");
printf("line 37\n");
char* buffer;
buffer = (char*) malloc(sizeof(psinfo_t));
printf("line 40\n");
if(file == NULL)
{
//perror("Error: Couldn't open file");
return;
}
fread((void *)buffer, sizeof(psinfo_t), 1, file);
psinfo_t* pData = (psinfo_t*) buffer;
time_t sTime=pData->pr_start.tv_sec;
int pr_pid=pData->pr_pid;
char* fname=pData->pr_fname;
free(buffer);
buffer = (char*) malloc(sizeof(stat));
stat(fullPath,buffer);
struct stat* fileStat=(struct stat*) buffer;
fclose(file);
int userId=fileStat->st_uid;
struct passwd* pw=getpwuid(userId);
char* uid=pw->pw_name;
printf("line 58\n");
if(isSetU<0){
//Print results
printf("%8s", uid);
if(isSetP>0)
printf(" %5d",pr_pid);
printf(" %16s %.24s\n", fname, ctime(&sTime));
free(buffer);
}else{
//Or else, add UID to UIDS if it didn't appear before
//check if UID is in UIDS
printf("line 70\n");
char * s2 = malloc(snprintf(NULL, 0, "%s:%d", "", userId) + 1);
printf("line 72\n");
snprintf(s2, "%s:%d", "", userId);
if(strstr(myUIDs,s2)!=NULL){
free(s2);
free(buffer);
return;
}
//If not, add to UIDS
printf("line 78\n");
free(s2);
printf("line 82\n");
char * ss = malloc(snprintf(NULL, 0, "%s:%d", "", 1) + 1);
printf("line 84\n");
sprintf(ss, "%s:%d", myUIDs, userId);
free(myUIDs);
myUIDs=ss;
free(buffer);
}
}
There are several issues I see on further review...
In a nutshell, the error you are getting does not appear to be the result of the line you're executing, rather, a side effect of a previous corruption of memory.
Where do you initialize myUIDs? It looks like you could be accessing it when it has not been defined based on the code provided
You are assigning fname from pData which is a pointer to the dynamically allocated buffer... which you subsequently free on the next line of execution, which means that fname is now pointing to deallocated memory. Yet you attempt to read from it later in the code... which may well be leading you off on a random walk through memory.
There are multiple instances in the code where you are dynamically allocating memory, and then attempting to use it without ever validating that you actually got the allocation you requested.
You are calling malloc() based on the return value from snprintf() without ever validating that snprintf() returned you a non-negative value. Though, I doubt this is an issue, it's unwise.
To be sure, the symptoms you are describing are the result of the corruption of the heap. The question is where. I would strongly recommend the use of valgrind.
In addition, if it is available, have a look at asprintf() instead of the malloc( snprintf() ) work you are doing.

winsock recv gives 10014 error

I'll start with the code:
typedef std::vector<unsigned char> CharBuf;
static const int RCV_BUF_SIZE = 1024;
SOCKET m_socket = a connected and working socket;
// ...
CharBuf buf; // Declare buffer
buf.resize(RCV_BUF_SIZE); // resize buffer to 1024
char* p_buf = reinterpret_cast<char*>(&buf[0]); // change from unsigned char to char
//char p_buf[RCV_BUF_SIZE];
int ret = recv(m_socket, p_buf, RCV_BUF_SIZE, 0); // Does not work
for (int i=0; i<RCV_BUF_SIZE; ++i) // Works (does not crash, so the buffer is ok)
char c = p_buf[i];
//...
Now when I run this code ret becomes -1 and WSAGetLastError() returns 10014 which means the pointer is bad.
However I can't see why this shouldn't work? If I comment out the reinterpret_cast line and use the line below it works!
It could be argued that reinterpret_cast is risky, but I think it should be ok as both unsigned char and signed char has the exact same size.
std::vectors should be safe to address directly in memory as far as I know as well.
The funny part is that when I do the same thing with the same vector-type in send() it works! Send function:
void SendData(const CharBuf& buf)
{
buf.resize(RCV_BUF_SIZE); // resize buffer to 1024
const char* p_buf = reinterpret_cast<const char*>(&buf[0]); // change from unsigned char to char
int ret = send(m_socket, p_buf, (int)buf.size(), 0); // Works
}
As we see, no difference except CharBuf being const in this case, can that change anything?
Why is recv() more sensitive than send()? How can recv() even know the pointer is invalid (which it obviously isn't)?? all it should see is a char array!
As per request my whole receive function (bear in mind that I can't spell out every function in it, but I think they should be fairly self-explanatory.
bool TcpSocket::ReceiveData(CharBuf* pData)
{
if (!CheckInitialized("ReceiveData"))
return false;
if (m_status != CONNECTED_STAT)
{
AddToErrLog("Socket not connected", 1, "ReceiveData");
return false;
}
int ret;
pData->resize(RCV_BUF_SIZE);
char* p_buf = reinterpret_cast<char*>(&pData[0]);
ret = recv(m_socket, p_buf, RCV_BUF_SIZE, 0);
switch (ret)
{
case 0: // Gracefully closed
AddToLog("Connection gracefully closed", 2);
Shutdown(); // The connection is closed, no idea to keep running
return true;
case SOCKET_ERROR: // Error
ret = WSAGetLastError();
if (ret == 10004) // This indicates the socket was closed while we were waiting
AddToLog("Socket was shut down while waiting for data", 1, "ReceiveData(1)");
else
AddToErrLog("Receive data failed with code: " + CStr(ret));
AddToLog("Connection ended with error", 2);
Shutdown();
return false;
default: // Normal operation
pData->resize(ret); // Remove unused space
return true;
}
}
Never mind. I found it while I was pasting the function. Like always, you find your error when you try to explain it for someone else :)
I leave it up to the reader to figure out what was wrong, but I'll give &pData[0] as a hint.
Thanks for your help :D
Found the answer myself while pasting the whole function, &pData[0] is a hint.