简体   繁体   中英

C++: segmentation fault in memset () when returning from procedure

Could anyone help me with my C++ program? I'm experiencing a segmentation fault and I can't find the problem. I'm writing a program for my raspberry pi that communicates with an nRF24L01 sensor network and sends data to a dashboard (Dashing) hosted on my RPi using CURL.

I ran my program with a debugger (gdb), and this is the backtrace I got: (see below for the full source code)

Program received signal SIGSEGV, Segmentation fault.
0xb6fbe0dc in memset () from /usr/lib/arm-linux-gnueabihf/libarmmem.so
(gdb) bt
#0  0xb6fbe0dc in memset () from /usr/lib/arm-linux-gnueabihf/libarmmem.so
#1  0x000119d4 in handleSensorMsg () at myNetworkMaster.cpp:174
#2  0x00000000 in ?? ()

I also checked my program with valgrind, using --leak-check=full. The output:

==20790== Invalid read of size 4
==20790==    at 0x484F808: bcm2835_peri_read (in /usr/local/lib/librf24.so.1.1.7)
==20790==  Address 0xffffffff is not stack'd, malloc'd or (recently) free'd
==20790==
==20790==
==20790== Process terminating with default action of signal 11 (SIGSEGV)
==20790==  Access not within mapped region at address 0xFFFFFFFF
==20790==    at 0x484F808: bcm2835_peri_read (in /usr/local/lib/librf24.so.1.1.7)
==20790==  If you believe this happened as a result of a stack
==20790==  overflow in your program's main thread (unlikely but
==20790==  possible), you can try to increase the size of the
==20790==  main thread stack using the --main-stacksize= flag.
==20790==  The main thread stack size used in this run was 8388608.
==20790==
==20790== HEAP SUMMARY:
==20790==     in use at exit: 75,908 bytes in 643 blocks
==20790==   total heap usage: 1,232 allocs, 589 frees, 84,668 bytes allocated
==20790==
==20790== LEAK SUMMARY:
==20790==    definitely lost: 0 bytes in 0 blocks
==20790==    indirectly lost: 0 bytes in 0 blocks
==20790==      possibly lost: 0 bytes in 0 blocks
==20790==    still reachable: 75,908 bytes in 643 blocks
==20790==         suppressed: 0 bytes in 0 blocks
==20790== Reachable blocks (those to which a pointer was found) are not shown.
==20790== To see them, rerun with: --leak-check=full --show-reachable=yes
==20790==
==20790== For counts of detected and suppressed errors, rerun with: -v
==20790== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

The source code: the crash occurs in handleSensorMsg(), after the first call to sendDataToDashBoard(). What happens is that the program starts and listens for messages on the nRF24L01. The first one it will receive is a sensor message. It reads the contents and sends the temperature data to the dashboard. After that it will crash. As you can see I'm not used to programming in C(++), my experience is limited to a few simple arduino programs.

 /** use Raspberry pi as master node for RF24Network, based on example code from TMRh20
  *
  * This example sketch shows how to manually configure a node via RF24Network as a master node, which
  * will receive all data from sensor nodes.
  *
  * send received data to Dashing dashboard using curl
  *
  * listen for messages on the program queue to send data to a node
  *
  */


#include <RF24/RF24.h>
#include <RF24Network/RF24Network.h>

#include <curl/curl.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <mqueue.h>

#include <time.h>

#include "common.h"

/**
 * g++ -L/usr/lib main.cc -I/usr/include -o main -lrrd
 **/
//using namespace std;

// CE Pin, CSN Pin, SPI Speed

// Setup for GPIO 22 CE and GPIO 25 CSN with SPI Speed @ 1Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_18, BCM2835_SPI_SPEED_1MHZ);

// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ); 

// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 8Mhz
RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ);  

RF24Network network(radio);

CURL *curl;
//CURLcode res;

mqd_t mq;

const char* AUTH_TOKEN = "MODEL_M";
const char* DASHBOARD_IP = "http://192.168.0.21:80/";

const int CURL_BUFFER_SIZE = 100;

class timer {
    private:
        time_t begTime;
    public:
    bool isRunning = false;

        void start() {
            begTime = time(NULL);
      isRunning = true;
        }

        int elapsedTime() {
            return (time(NULL) - begTime);
        }

        bool isTimeout(int seconds) {
      int elapsed = elapsedTime();
      //printf("%f\n", elapsed);
            return elapsed >= seconds;
        }
};

const int AVG_TEMP_SAMPLESIZE = 60;
const float TEMP_HIVAL = 999;
const float TEMP_LOVAL = -273.15;
const int DAILY_TEMP_RST_HOUR = 0;
float avgTemperature = TEMP_HIVAL;
float minTemperature = TEMP_HIVAL;
float maxTemperature = TEMP_LOVAL;
float minDailyTemp = TEMP_HIVAL;
float maxDailyTemp = TEMP_LOVAL;

// TODO: create 'message queue'?
const int SEND_RELAY_INTERVAL = 1;
timer relayMsgTimer;
const int SEND_DASH_WAIT = 1;
timer relayDashTimer;
const int SEND_QUERY_INTERVAL = 10;
timer queryMsgTimer;

bool timedRelayMode = true;
int timedRelayState = 1;
const int TIMED_RELAY_ON_HOUR = 6;
const int TIMED_RELAY_OFF_HOUR = 0;
const int TIMED_RELAY_RST_HOUR = 12;

void setCurrentTimestamp(char* timestamp) {

  time_t rawTime = time(NULL);
  struct tm *tm = localtime(&rawTime);
  strftime(timestamp, 20, "%Y-%m-%d %H:%M:%S", tm);

}

void sendDataToDashBoard(const char* const widget, const char* const data) {

  char url[CURL_BUFFER_SIZE];
  char postFields[CURL_BUFFER_SIZE];

  std::fill(url, url + CURL_BUFFER_SIZE, 0);
  std::fill(postFields, postFields + CURL_BUFFER_SIZE, 0);

  sprintf(url, "%swidgets/%s", DASHBOARD_IP, widget);
    curl_easy_setopt(curl, CURLOPT_URL, url);

    sprintf(postFields, "{\"auth_token\":\"%s\",%s", AUTH_TOKEN, data);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postFields);

  printf("%s%s\n", url, postFields);

    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK)
      printf("curl_easy_perform failed: %s\n", curl_easy_strerror(res));
    curl_easy_reset(curl);

} // <-- this is where the debugger stops !!!

void handleSensorMsg() {

  RF24NetworkHeader header = 0;
  network.read(header,&sensorData,sizeof(sensorData));
  char timestamp[20];
  std::fill(timestamp, timestamp + 20, 0);
  setCurrentTimestamp(timestamp);
  printf("%s - %c: Rcv %d %u from 0%o\n", timestamp, SENSOR_MSG, sensorData.temperature, sensorData.humidity, header.from_node);

  // ignore probable invalids -- TODO: what if first reading is invalid? => avgTemperature
  if (header.from_node != SENSOR_NODE ||
      (avgTemperature != TEMP_HIVAL &&
        (sensorData.temperature > avgTemperature * 20.0 ||
         sensorData.temperature < avgTemperature * 5.0))) {
    printf("ignored invalid data\n");
    return;
  }

  float temperature = sensorData.temperature / 10.0;
  int humidity = sensorData.humidity / 10.0 + 0.5;

  if (avgTemperature == TEMP_HIVAL)
    avgTemperature = temperature;
  else {
    avgTemperature -= avgTemperature / AVG_TEMP_SAMPLESIZE;
    avgTemperature += temperature / AVG_TEMP_SAMPLESIZE;
  }

  if (temperature > maxDailyTemp) {
    maxDailyTemp = temperature;
    if (temperature > maxTemperature)
      maxTemperature = temperature;
  } else if (temperature < minDailyTemp) {
    minDailyTemp = temperature;
    if (temperature < minTemperature)
      minTemperature = temperature;
  }

  char data[CURL_BUFFER_SIZE];
  std::fill(data, data + CURL_BUFFER_SIZE, 0);
  sprintf(data, "\"current\":%.1f,\"average\":%f,\"moreinfo\":\"Min : %.1f (%.1f) - Max : %.1f (%.1f)\"}",
                    temperature, avgTemperature, minDailyTemp, minTemperature, maxDailyTemp, maxTemperature);
  sendDataToDashBoard("temperature", data); // This is the call that crashes!!!

  std::fill(data, data + CURL_BUFFER_SIZE, 0);
  sprintf(data, "\"value\":%d}", humidity);
  sendDataToDashBoard("humidity", data);

}

void handleRelayMsg() {

  RF24NetworkHeader header = 0;
  network.read(header, &relayData, sizeof(relayData));
  char timestamp[20];
  std::fill(timestamp, timestamp + 20, ' ');
  setCurrentTimestamp(timestamp);
  printf("%s - %c: Rcv %d from 0%o\n", timestamp, RELAY_MSG, relayData.state, header.from_node);

  // handle invalid reading
  if (header.from_node != RELAY_NODE ||
      (relayData.state != true && relayData.state != false)) {
    printf("ignored invalid data\n");
    queryMsgTimer.start();
    return;
  }

  // delay send of relayData to dashboard to avoid race condition
  relayDashTimer.start();

  relayMsgTimer.isRunning = false;
  queryMsgTimer.isRunning = false;

}

bool sendRelayData() {

  RF24NetworkHeader header(/*to node*/ RELAY_NODE, RELAY_MSG);
  char timestamp[20];
  std::fill(timestamp, timestamp + 20, ' ');
  setCurrentTimestamp(timestamp);
    printf("%s - %c: Snd %d to %o\n", timestamp, RELAY_MSG, relayData.state, RELAY_NODE);
  if (!network.write(header, &relayData, sizeof(relayData))) {

    relayMsgTimer.start();
    printf("Send failed...\n");
    return false;

  }

  printf("Send OK\n");
  return true;

}

void sendQueryMsgToRelay() {

  RF24NetworkHeader header(/*to node*/ RELAY_NODE, QUERY_MSG);
  char timestamp[20];
  std::fill(timestamp, timestamp + 20, ' ');
  setCurrentTimestamp(timestamp);
    printf("%s - %c: Snd to %o\n", timestamp, QUERY_MSG, RELAY_NODE);
  if (!network.write(header, NULL, 0)) {
    queryMsgTimer.start();
    printf("Send failed...\n");
    return;
  }

  printf("Send OK\n");
  queryMsgTimer.isRunning = false;

}

bool readMessageQueue() {

  ssize_t bytes_read;
  char buffer[MAX_SIZE + 1];
  std::fill(buffer, buffer + MAX_SIZE + 1, ' ');

  /* receive the message */
  bytes_read = mq_receive(mq, buffer, MAX_SIZE, NULL);
  if (bytes_read >= 0) {

    buffer[bytes_read] = '\0';
    char timestamp[20];
    std::fill(timestamp, timestamp + 20, ' ');
    setCurrentTimestamp(timestamp);
    printf("%s - Received: %s\n", timestamp, buffer);

    if (!strncmp(buffer, MSG_ON, strlen(MSG_ON))) {

      if (relayMsgTimer.isRunning)
        return false;

      relayData.state = true;
      queryMsgTimer.isRunning = false;
      sendRelayData();

    } else if (!strncmp(buffer, MSG_OFF, strlen(MSG_OFF))) {

      if (relayMsgTimer.isRunning)
        return false;

      relayData.state = false;
      queryMsgTimer.isRunning = false;
      sendRelayData();

    } else if (!strncmp(buffer, MSG_SET, strlen(MSG_SET))) {

      if (relayMsgTimer.isRunning)
        return false;

      relayData.state = !relayData.state;
      queryMsgTimer.isRunning = false;
      sendRelayData();

    } else if (!strncmp(buffer, MSG_GET, strlen(MSG_GET))) {

      if (queryMsgTimer.isRunning)
        return false;

      sendQueryMsgToRelay();

    } else if (!strncmp(buffer, MSG_TIMER, strlen(MSG_TIMER))) {

      timedRelayMode = !timedRelayMode;
      timedRelayState = 1;
      printf("timedRelayMode=%d\n", timedRelayMode);

    } else if (!strncmp(buffer, MSG_STOP, strlen(MSG_STOP)))

      return true;

  }

  return false;

}

void sendRelayDataToDashboard() {

  char data[CURL_BUFFER_SIZE];
  std::fill(data, data + CURL_BUFFER_SIZE, 0);
  sprintf(data, "\"status\":\"%s\"}", relayData.state ? "ON" : "OFF");
  sendDataToDashBoard("relay", data);

  relayDashTimer.isRunning = false;

}

int getCurrentHour() {

  time_t rawTime = time(NULL);
  struct tm *tm = localtime(&rawTime);
  return tm->tm_hour;

}

void setTimedRelayState() {

  char timestamp[20];
  std::fill(timestamp, timestamp + 20, ' ');
  setCurrentTimestamp(timestamp);
  printf("%s - Timed relay event:\n", timestamp);
  relayData.state = !relayData.state;
  sendRelayData();

}

void updateTimedRelay(int hour) {

  if (timedRelayState == 1 && relayData.state && hour == TIMED_RELAY_OFF_HOUR) {

    setTimedRelayState();
    timedRelayState = 2;

  } else if (timedRelayState == 2 && !relayData.state && hour == TIMED_RELAY_ON_HOUR) {

    setTimedRelayState();
    timedRelayState = 1;

  } else if (timedRelayState == 2 && hour == TIMED_RELAY_RST_HOUR)
    timedRelayState = 1;

}

void updateDailyTemperature(int hour) {

  if (hour == DAILY_TEMP_RST_HOUR) {

    char timestamp[20];
    std::fill(timestamp, timestamp + 20, ' ');
    setCurrentTimestamp(timestamp);
    minDailyTemp = avgTemperature;
    maxDailyTemp = avgTemperature;
    printf("%s - daily temperatures reset\n", timestamp);

  }

}

int main(int argc, char** argv) 
{
    // Refer to RF24.h or nRF24L01 DS for settings

    radio.begin();

    delay(5);
    network.begin(CHANNEL, MASTER_NODE);

    radio.setDataRate(RF24_250KBPS);
  radio.setCRCLength(RF24_CRC_8);

  // increase delay for network ACK
  network.routeTimeout = 300;

    radio.printDetails();

  // CURL setup for sending data to dashboard
  curl_global_init(CURL_GLOBAL_ALL);
  curl = curl_easy_init();
  if (curl == NULL) {
    printf("Error getting curl handle.\n");
    exit(EXIT_FAILURE);
  }

  // setup the message queue
  struct mq_attr attr;

  /* initialize the queue attributes */
  attr.mq_flags = 0;
  attr.mq_maxmsg = 10;
  attr.mq_msgsize = MAX_SIZE;
  attr.mq_curmsgs = 0;

  /* create the message queue */
  mq = mq_open(QUEUE_NAME, O_CREAT | O_RDONLY | O_NONBLOCK, 0644, &attr);
  if (mq == -1) {
    printf("Failed to create queue.\n");
    exit(EXIT_FAILURE);
  }

  queryMsgTimer.start();
  int currentHour = getCurrentHour();
  bool exitReceived = false;

    while(!exitReceived)
    {

      network.update();
      while ( network.available() ) {       // Is there anything ready for us?

          RF24NetworkHeader header;           // If so, grab it and print it out
      network.peek(header);

      switch(header.type) {

        case SENSOR_MSG: handleSensorMsg();
                         break;

        case RELAY_MSG: handleRelayMsg();
                        break;

        default:  network.read(header,0,0);
                  char timestamp[20];
                  setCurrentTimestamp(timestamp);
                  printf("%s - Rcv bad type %d from 0%o\n", timestamp, header.type, header.from_node);
                  printf("%s\n", header.toString());
                  break;

      }

    }

    // check for incoming messages on the program queue
    exitReceived = readMessageQueue();

    // are there any messages that need to be sent?
    if (relayMsgTimer.isRunning && relayMsgTimer.isTimeout(SEND_RELAY_INTERVAL))
      relayMsgTimer.isRunning = !sendRelayData();

    if (relayDashTimer.isRunning && relayDashTimer.isTimeout(SEND_DASH_WAIT))
      sendRelayDataToDashboard();

    if (queryMsgTimer.isRunning && queryMsgTimer.isTimeout(SEND_QUERY_INTERVAL))
      sendQueryMsgToRelay();

    // timed events
    if (currentHour != getCurrentHour()) {

      currentHour = getCurrentHour();
      // check if relay needs to be switched on or off based on timer
      if (timedRelayMode)
        updateTimedRelay(currentHour);

      // reset daily temperature min&max
      updateDailyTemperature(currentHour);

    }

    delay(100);
    fflush(stdout);

  }

  /* cleanup */
  curl_easy_cleanup(curl);
  curl_global_cleanup();
  mq_close(mq);
  mq_unlink(QUEUE_NAME);

    return 0;

}

The common.h include:

#ifndef COMMON_H_
#define COMMON_H_

#define CHANNEL       1

#define QUEUE_NAME  "/rf24_queue"
#define MAX_SIZE    1024
#define MSG_STOP    "exit"
#define MSG_ON      "ON"
#define MSG_OFF     "OFF"
#define MSG_SET     "SET"
#define MSG_GET     "GET"
#define MSG_TIMER   "TIMER"

#define MASTER_NODE 0
#define SENSOR_NODE 01
#define RELAY_NODE  01

#define SENSOR_MSG  '1'
#define RELAY_MSG   'R'
#define QUERY_MSG   'Q'

#ifndef AM2320_H
struct sensorData_t {
  int16_t temperature;
  uint16_t humidity;
} sensorData;
#endif

struct relayData_t {
  bool state;
} relayData;

typedef enum { wdt_16ms = 0, wdt_32ms, wdt_64ms, wdt_128ms, wdt_250ms, wdt_500ms, wdt_1s, wdt_2s, wdt_4s, wdt_8s } wdt_prescalar_e;

#endif /* #ifndef COMMON_H_ */

The RF24 libraries are available from here: https://github.com/TMRh20/RF24 . Thanks for your time!

The offending code was this block here (in sendDataToDashBoard):

CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
  printf("curl_easy_perform failed: %s\n", curl_easy_strerror(res));
curl_easy_reset(curl);

I commented out the curl_easy_reset() call and now it doesn't crash anymore. I don't know why, but there you have it. I think I don't need to do a reset since I always set the same options on every perform (URL & POSTFIELDS), so this works for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM