Strange If Statement Behavior on ESP32-S3

ryaber24
Posts: 1
Joined: Mon Mar 11, 2024 5:50 pm

Strange If Statement Behavior on ESP32-S3

Postby ryaber24 » Mon Mar 11, 2024 5:59 pm

Hello! I am working on a project and writing a custom library, in which I have found a weird if statement bug.

Here is my .h file:

Code: Select all

#include <Arduino.h>
#include <ArduinoJson.h>
#include <painlessMesh.h>
#include <UARTProtocol.h>
#include <EasyTransfer.h>

#ifndef NMESHMANAGE_H
#define NMESHMANAGE_H

#define DEFAULTPAQARRAY {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}

class sensor {
    public:
        int ID;
        int outerID;
        int axis;

        int *axisIDs;
        char **axisVals;

        //0 = pending certification
        //1 = ready to request
        //2 = pending response
        int *state;
        
        sensor *nextSensor;

        char encryptString[65];

        unsigned long lastReqTime[9];
};

class Paq {
    public:
        int PaqID;
        int reqCount;
        int PaqsCollected;

        unsigned long birthday;

        int *waitingOn;

        int *axisIds;
        const char **axisLbls;
        float *data;
    Paq () { PaqsCollected = 0; reqCount = 0;}
};

//initialize the connection of a sensor
//return vals
//0 = success
//1 = 
int initSensor(uint32_t from, painlessMesh &mesh, DynamicJsonDocument &msgDoc);

//validate encrypt
//0 = success
//1 = incorrect
//2 = fail
int validateSensor(int ID, char* cypher);

//request neccessary data
//0 = success
//1 = 
int requestData(painlessMesh &mesh);

//handle incoming data
//0 = success
//1 = failed to match paq id
int handlePaq(uint32_t from, DynamicJsonDocument &msgDoc, SEND_DATA_STRUCTURE &txpaq, EasyTransfer &UARTout);

int disconnectSensor(int ID);


//0 = all good
//1 = lagger found
int findLaggers();

//polling rate lookup table
//in hertz

int pollingPeriodLookup(const char* tag);

int PollSensorsConnected();

#endif
Here is my .cpp file:

Code: Select all

#include <Arduino.h>
#include <ArduinoJson.h>
#include <painlessMesh.h>
#include <Cipher.h>
#include <UARTProtocol.h>
#include <EasyTransfer.h>

#include <newMeshManage.h>

#define PAQ_TIMEOUT 5000

int sensorsConnected;
int axisConnected;

int validatedSensors;

int packCount;

int lastCheckedPaq;
int lastCheckedID;

sensor *firstSens;

char* key = "bUcgPYcMfmYSZAWF";
Cipher * cipher = new Cipher();

Paq *paqArray[20] = DEFAULTPAQARRAY; //number can be changed but this is basically the amount of open paqs we can manage at a time
                    //only stores 2 ints so memory usage is very small
int openPaqs = 0;

void cryptoString(int length, char* output) {

    char* eligible_chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890";
    randomSeed(esp_random());

    for (int i = 0; i < length; i++) {
        uint8_t random_index = random(0, 61);
        *output = eligible_chars[random_index];
        output++;
    }
}

int initSensor(uint32_t from, painlessMesh &mesh, DynamicJsonDocument &msgDoc) {

    Serial.println("MESH: INIT NEW SENSOR");

    sensor *newSens = new sensor;

    newSens->outerID = from;
    newSens->axis = msgDoc["axis"];

    if (sensorsConnected == 0) {
        firstSens = newSens;
    } else {
        sensor *newest = firstSens;
        
        for (int i = 1; i < sensorsConnected; i++) {
            newest = newest->nextSensor;
        }
        newest->nextSensor = newSens;
    }



    newSens->axisVals = new char*[newSens->axis];
    for (int i = 0; i < newSens->axis; i++) {
        newSens->axisVals[i] = new char[6];
    }

    newSens->axisIDs = new int[newSens->axis];

    for (int i = 0; i < newSens->axis; i++) {
        strcpy(newSens->axisVals[i], msgDoc["axisTags"][i]);
        axisConnected ++;
        newSens->axisIDs[i] = axisConnected;
    }

    newSens->state = new int[newSens->axis];
    for (int i = 0; i < newSens->axis; i++) {
        newSens->state[i] = 0;
    }

    sensorsConnected ++;

    StaticJsonDocument<1024> doc;


    doc["to"] = from;

    cipher->setKey(key);
    
    char encryptString[65];
    encryptString[64] = '\0';

    cryptoString(64, encryptString);


    strcpy(newSens->encryptString, encryptString);

    doc["crypt"] = cipher->encryptString(encryptString);
    
    String tempString = doc["crypt"];


    newSens->ID = sensorsConnected;

    doc["newID"] = newSens->ID;

    doc["topic"] = "cert";

    char msgOut[measureJson(doc)];

    serializeJson(doc, msgOut, measureJson(doc));

    mesh.sendSingle(from, msgOut);

    return 0;
}

int validateSensor(int ID, char* cypher) {

    Serial.println("MESH: VALIDATING SENSOR");

    unsigned long timeTag = millis();

    bool matchedID;
    sensor *match = firstSens;
    for (int i = 0; i < sensorsConnected; i++) {
        if (match->ID == ID) {
            matchedID = true;
            break;
        } else {
            for (int z = 0; z < 9; z++) {
                match->lastReqTime[z] = timeTag;
            }
            match = match->nextSensor;
        }
    }
    

    if (matchedID != true) {
        return 2;
        //should delete sensor and likely send NACK packet
    }

    if (strcmp(match->encryptString, cypher) == 0) {
        validatedSensors ++;
        for (int i = 0; i < match->axis; i++) {
            match->state[i] = 1;
        }  
        Serial.println("MESH: VALIDATING SUCCESS");
        return 0;
    } else {
        for (int i = 0; i < match->axis; i++) {
            delete match->axisVals[i];
        }
        delete match->axisIDs;
        delete match;
        return 1;
    }
    return 2;
}

int requestData(painlessMesh &mesh) {
    
    sensor *accessPtr = firstSens;
    StaticJsonDocument<1024> msg;
    bool haveNeed = false;
    int reqs = 0;
    JsonObject temp = msg.createNestedObject("need");

    unsigned long currentTime = millis();

    int waitOnBuilder[validatedSensors];

    for (int i = 0; i < validatedSensors; i++) {
        if (!i == 0) {
            accessPtr = accessPtr->nextSensor;
        }

        JsonObject need = temp.createNestedObject(String(accessPtr->ID));
        for (int z = 0; z < accessPtr->axis; z++) {

            int pollingPeriod = pollingPeriodLookup(accessPtr->axisVals[z]);
            if ((currentTime - accessPtr->lastReqTime[z] >= pollingPeriod*1000 - 10) && (accessPtr->state[z] == 1)) { //-10 for travel time, can be optimized
                need[String(z)] = 1;
                haveNeed = true;
                accessPtr->lastReqTime[z] = currentTime;
                accessPtr->state[z] = 2;

                waitOnBuilder[reqs] = accessPtr->axisIDs[z];

                reqs++;
            } else {
                need[String(z)] = 0;
            }
        }
    }
    if (haveNeed == true) {
        msg["topic"] = "req";
        msg["paqID"] = packCount;

        Paq *newPaq = new Paq;
        newPaq->PaqID = packCount;
        newPaq->reqCount = reqs;

        newPaq->data = new float[reqs];
        newPaq->axisIds = new int[reqs];
        newPaq->axisLbls = new const char*[reqs];
        newPaq->waitingOn = new int[reqs];

        for (int i = 0; i < reqs; i++) {
            Serial.println(i);
            newPaq->waitingOn[i] = waitOnBuilder[i];
        }

        newPaq->birthday = millis();
        //for (int i = 0; i < reqs; i++) {
        //    newPaq->axisLbls[i] = new char[6];
        //}
        paqArray[openPaqs] = newPaq;
        openPaqs++;

        char docOut[measureJson(msg)];
        serializeJson(msg, docOut, measureJson(msg));
        serializeJson(msg, Serial);

        mesh.sendBroadcast(docOut);
        Serial.println("MESH: SENT DATA REQ");
        packCount ++;
    }
    return 0;
}

int handlePaq(uint32_t from, DynamicJsonDocument &msgDoc, SEND_DATA_STRUCTURE &txpaq, EasyTransfer &UARTout) {

    Serial.println("MESH: HANDLING PAQ");

    if (msgDoc["ID"] == lastCheckedID && msgDoc["paqID"] == lastCheckedPaq) {
        Serial.print("DUPEPAQ: ");
        Serial.println(int(msgDoc["paqID"]));
        return 1;
    }

    Paq *accessPtr = nullptr;
    for (int i = 0; i < openPaqs; i++) {
        if (paqArray[i]->PaqID == msgDoc["paqID"]) {
            accessPtr = paqArray[i];
            break;
        }
    }
    if (accessPtr == nullptr) {
        Serial.println("NULLPAQREFERENCED");
        return 1;
    }
    
    sensor *sensPtr = firstSens;
    while (1) {
        if (sensPtr->ID == msgDoc["ID"]) {
            break;
        } else {
            sensPtr = sensPtr->nextSensor;
        }
    }

    lastCheckedID = msgDoc["ID"];
    lastCheckedPaq = msgDoc["paqID"];

    int dataAdded = 0;

    for (int i = 0; i < msgDoc["data"].size(); i++) {

        String test = msgDoc["data"][i];

        if (strcmp("null", test.c_str()) == 0) {
            Serial.println("null got");
            continue;
        }

        accessPtr->axisIds[i + accessPtr->PaqsCollected] = sensPtr->axisIDs[i];
        accessPtr->data[i + accessPtr->PaqsCollected] = msgDoc["data"][i];
        accessPtr->axisLbls[i + accessPtr->PaqsCollected] = sensPtr->axisVals[i];

        sensPtr->state[i] = 1;

        dataAdded ++;
    }

    if (dataAdded == 0) {
        return 0;
    }

    accessPtr->PaqsCollected += dataAdded;

    if (accessPtr->PaqsCollected == accessPtr->reqCount) {
        Serial.println(accessPtr->PaqsCollected == accessPtr->reqCount);
        Serial.print("reqs");
        Serial.println(accessPtr->reqCount);
        Serial.print("collect");
        Serial.println(accessPtr->PaqsCollected);
        Serial.println(uxTaskGetStackHighWaterMark(NULL));

        SEND_DATA_STRUCTURE txdata;
        txdata.parts = (accessPtr->PaqsCollected + 16) / 16;

        int offset = 0;
        bool catchEnd = false;
        int count = 0;

        for (int i = 0; i < accessPtr->PaqsCollected; i++) {

            txdata.data[i - offset] = accessPtr->data[i];
            txdata.ids[i - offset] = accessPtr->axisIds[i];

            strcpy(txdata.axislbl[i - offset], accessPtr->axisLbls[i]);


            txdata.recieptType = 0;
            txdata.status = 1;
            
            if (i+1 >= 16 + offset) {
                txpaq = txdata;
                SEND_DATA_STRUCTURE temp;
                txdata = temp;
                txdata.parts = (accessPtr->PaqsCollected + 16) / 16;
                UARTout.sendData();
                offset += 16;
            }
            if (i + 1 == 48) {
                catchEnd = true;
            }
            count ++;
        }
        if (catchEnd == false) {
            txpaq = txdata;
            strcpy(txpaq.axislbl[count - offset], "null_");
            Serial.println("PACK TRANSFERED");
            UARTout.sendData();
        }

        //for (int i = 0; i < accessPtr->reqCount; i++) {
        //    delete[] accessPtr->axisLbls[i];
        //} 

        delete[] accessPtr->data;
        delete[] accessPtr->axisIds;
        delete[] accessPtr->axisLbls;
        delete[] accessPtr->waitingOn;

        //paqArray[openPaqs - 1] = nullptr;
        delete accessPtr;
        openPaqs --;


        return 0;
    }
}

int disconnectSensor(int ID) {
    for (int i = 0; i < sensorsConnected; i++) {
        
    }
}

int findLaggers() {
    Paq *paqptr;
    for (int i = 0; i < openPaqs; i++) {
        paqptr = paqArray[i];
        if (paqptr == nullptr) {
            break;
        } else {
            if (millis() - paqptr->birthday >= PAQ_TIMEOUT) {
                sensor *sensPtr = firstSens;
                for (int z = 0; z < sensPtr->axis; z++) {
                    for (int y = 0; y < paqptr->reqCount; y++) {
                        if (sensPtr->axisIDs[z] == paqptr->waitingOn[y]) {
                            sensPtr->state[z] = 1;
                        }
                    }
                }

                delete[] paqptr->data;
                delete[] paqptr->axisIds;
                delete[] paqptr->axisLbls;
                delete[] paqptr->waitingOn;
                delete paqptr;

                for (int z = 0; z < openPaqs - i; z++) {
                    paqArray[i - z] = paqArray[i - z + 1];
                }
                openPaqs --;
                return 1;
            }
        }
    }
    return 0;
}

int pollingPeriodLookup(const char* tag) {
    if (strcmp(tag, "bme_t") == 0) {
        return 1;
    }
    if (strcmp(tag, "bme_p") == 0) {
        return 1;
    }
    if (strcmp(tag, "bme_h") == 0) {
        return 1;
    }
    if (strcmp(tag, "therm") == 0) {
        return 1;
    } //add as sensors are developed
    return 1;
}

int PollSensorsConnected() {
    return validatedSensors;
}
Pretty much no matter what, the if statement in the handlePaq function, "if (accessPtr->PaqsCollected == accessPtr->reqCount)" evaluates to true. I am printing the values of those integers inside the if statement, and I can clearly see that they are not equal. If I print the value of that bool outside of the if statement, it is false, but if I print it inside, it is true. It doesn't matter if I assign the integers to local or global variables and then evaluate them in the if statement. The only way I have gotten the if statement to return false is by literally writing if (false). I have tried increasing stack size increase it is some weird memory error to no avail. I also tried disabling compiler optimization to no avail. It may be something dumb I'm overlooking, I am unsure. Any help is greatly appreciated. Thank you!

ESP_Sprite
Posts: 9764
Joined: Thu Nov 26, 2015 4:08 am

Re: Strange If Statement Behavior on ESP32-S3

Postby ESP_Sprite » Tue Mar 12, 2024 3:04 am

Hm, only thing I see is that you might have an access-after-free situation, as you delete accessPtr, which frees the memory associated with the paqArray entry it points at, but then you don't set the paqArray entry to NULL or something, meaning the next iteration will still access the memory there as if it is valid.

Who is online

Users browsing this forum: No registered users and 114 guests