Home > Software design >  Trouble pinpointing source of uninitialized value
Trouble pinpointing source of uninitialized value

Time:05-10

I am writing a simple earthquake detection program for the BeagleBone Green using a vibration sensor that I have hooked up, together with a cape that has a built in accelerometer and digit display. The brains of the earthquake detector are located in the EarthquakeDetector class.

earthquake_detector.h:

#pragma once
#include <atomic>
#include <thread>

#include <Accelerometer/accelerometer.h>
#include <DigitDisplay/digit_display.h>
#include <VibrationSensor/vibration_sensor.h>

namespace earthquake_detection_unit {

class EarthquakeDetector {
public:
    EarthquakeDetector();
    ~EarthquakeDetector();

private:
    // Worker thread for continuous earthquake monitoring.
    void Worker();

    // Monitors accelerometer readings. This function returns after a certain 
    // number of consecutive low readings.
    void AccelerometerMonitor();

    // Displays current magnitude on the digit display.
    void DisplayMagnitude();

    // Worker thread member variable.
    std::thread worker_thread;
    // Signal to shutdown worker thread.
    std::atomic<bool> shutdown;

    // Pointers to devices.
    Accelerometer *accelerometer;
    DigitDisplay *digit_display;
    VibrationSensor *vibration_sensor;
};

} // earthquake_detection_unit

earthquake_detector.cc:

#include <iostream>

#include "earthquake_detector.h"

namespace earthquake_detection_unit {

const double kScaleValue1Threshold = 0.144;
const double kScaleValue2Threshold = 0.281;
const double kScaleValue3Threshold = 0.418;
const double kScaleValue4Threshold = 0.555;
const double kScaleValue5Threshold = 0.692;
const double kScaleValue6Threshold = 0.829;
const double kScaleValue7Threshold = 0.966;
const double kScaleValue8Threshold = 1.103;
const double kScaleValue9Threshold = 1.24;

const int kAccelerometerTimeoutTotal_ms = 10000;
const int kAccelerometerSamplePeriod_ms = 100;
const int kAccelerometerTimeoutNumPeriods = kAccelerometerTimeoutTotal_ms / kAccelerometerSamplePeriod_ms;

EarthquakeDetector::EarthquakeDetector() : shutdown(false) {
    // Initialize digit display.
    digit_display = new DigitDisplay();

    worker_thread = std::thread(&EarthquakeDetector::Worker, this);
}

EarthquakeDetector::~EarthquakeDetector() {
    shutdown.store(true, std::memory_order_relaxed);
    worker_thread.join();

    // Shutdown digit display.
    delete digit_display;
}

void EarthquakeDetector::Worker() {
    while (!shutdown) {
        std::cout << "\t<EarthquakeDetector> ";
        std::cout << "Launching vibration sensor to listen for a vibration." << std::endl;
        // First, wait for a vibration.
        vibration_sensor = new VibrationSensor();
        vibration_sensor->WaitForVibration();
        delete vibration_sensor;

        // After detecting a vibration, launch accelerometer.
        std::cout << "\t<EarthquakeDetector> ";
        std::cout << "Vibration detected -- vibration sensor shutdown, launching accelerometer." << std::endl;
        accelerometer = new Accelerometer();

        // Monitor accelerometer readings.
        AccelerometerMonitor();

        // Flash magnitude.
        digit_display->FlashDisplay();
        // Reset digit display to display 0.
        digit_display->SetDigit(0);

        // Shutdown accelerometer for lack of activity.
        std::cout << "\t<EarthquakeDetector> ";
        std::cout << "Shutting down accelerometer due to inactivity." << std::endl;
        delete accelerometer;
    }
}

void EarthquakeDetector::AccelerometerMonitor() {
    // This function returns if we obtain kAccelerometerTimeoutNumPeriods
    // consecutive low readings from the accelerometer.
    int consecutive_readings = 0;
    while (consecutive_readings != kAccelerometerTimeoutNumPeriods) {
        DisplayMagnitude();
        if (accelerometer->GetCurrentReading() >= kScaleValue1Threshold) {
            consecutive_readings = 0;
        }
        else {
              consecutive_readings;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(kAccelerometerSamplePeriod_ms));
    }
}

void EarthquakeDetector::DisplayMagnitude() {
    double acc_reading = accelerometer->GetHighestReading();

    unsigned int digit_to_display = 0;
    if (acc_reading >= kScaleValue9Threshold) {
        digit_to_display = 9;
    }
    else if (acc_reading >= kScaleValue8Threshold) {
        digit_to_display = 8;
    }
    else if (acc_reading >= kScaleValue7Threshold) {
        digit_to_display = 7;
    }
    else if (acc_reading >= kScaleValue6Threshold) {
        digit_to_display = 6;
    }
    else if (acc_reading >= kScaleValue5Threshold) {
        digit_to_display = 5;
    }
    else if (acc_reading >= kScaleValue4Threshold) {
        digit_to_display = 4;
    }
    else if (acc_reading >= kScaleValue3Threshold) {
        digit_to_display = 3;
    }
    else if (acc_reading >= kScaleValue2Threshold) {
        digit_to_display = 2;
    }
    else if (acc_reading >= kScaleValue1Threshold) {
        digit_to_display = 1;
    }

    digit_display->SetDigit(digit_to_display);
}

} // earthquake_detection_unit

Problem: Valgrind complains about an unitialized unsigned int (I used the --track-origins=yes option) and I can't find where I could possibly have an unitialized value in my implementation. I get the following error several times, presumably because as the code is being executed, it's falling through the line of if-statements in DisplayMagnitude.

==1023== Thread 2:
==1023== Conditional jump or move depends on uninitialised value(s)
==1023==    at 0x10A2DA: earthquake_detection_unit::EarthquakeDetector::DisplayMagnitude() (earthquake_detector.cc:85)
==1023==    by 0x10A227: earthquake_detection_unit::EarthquakeDetector::AccelerometerMonitor() (earthquake_detector.cc:70)
==1023==    by 0x10A15B: earthquake_detection_unit::EarthquakeDetector::Worker() (earthquake_detector.cc:51)
==1023==    by 0x10B705: void std::__invoke_impl<void, void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(std::__invoke_memfun_deref, void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:73)
==1023==    by 0x10B633: std::__invoke_result<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>::type std::__invoke<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:95)
==1023==    by 0x10B5A1: void std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::_M_invoke<0u, 1u>(std::_Index_tuple<0u, 1u>) (thread:244)
==1023==    by 0x10B53F: std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::operator()() (thread:251)
==1023==    by 0x10B515: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> > >::_M_run() (thread:195)
==1023==    by 0x48FAA69: ??? (in /usr/lib/arm-linux-gnueabihf/libstdc  .so.6.0.22)
==1023==  Uninitialised value was created by a heap allocation
==1023==    at 0x4840194: operator new(unsigned int) (vg_replace_malloc.c:415)
==1023==    by 0x10A147: earthquake_detection_unit::EarthquakeDetector::Worker() (earthquake_detector.cc:48)
==1023==    by 0x10B705: void std::__invoke_impl<void, void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(std::__invoke_memfun_deref, void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:73)
==1023==    by 0x10B633: std::__invoke_result<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>::type std::__invoke<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*>(void (earthquake_detection_unit::EarthquakeDetector::*&&)(), earthquake_detection_unit::EarthquakeDetector*&&) (invoke.h:95)
==1023==    by 0x10B5A1: void std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::_M_invoke<0u, 1u>(std::_Index_tuple<0u, 1u>) (thread:244)
==1023==    by 0x10B53F: std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> >::operator()() (thread:251)
==1023==    by 0x10B515: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (earthquake_detection_unit::EarthquakeDetector::*)(), earthquake_detection_unit::EarthquakeDetector*> > >::_M_run() (thread:195)
==1023==    by 0x48FAA69: ??? (in /usr/lib/arm-linux-gnueabihf/libstdc  .so.6.0.22)

I'm wondering if someone could point me in the right direction of what could possibly be causing these errors. I have looked at various SO posts on similar issues but nothing really seemed to apply to my situation. Thanks!

Edit 1: Stripped down version of the accelerometer interface. I edited out a lot of the I2C file reading and writing to make this as brief as possible.

accelerometer.h:

namespace earthquake_detection_unit {

class Accelerometer {
public:
    typedef struct Vector {
        Vector(int16_t x_reading, int16_t y_reading, int16_t z_reading);

        double x;
        double y;
        double z;
        double magnitude;
    } Vector;

    Accelerometer();
    ~Accelerometer();

    inline double GetCurrentReading() { return current_reading; }
    inline double GetHighestReading() { return highest_reading; }

private:
    // Worker thread for sampling accelerometer readings.
    void Worker();

    void CollectReading();

    void ActivateAccelerometer();
    void ShutDownAccelerometer();

    // Signal to shutdown worker thread.
    std::atomic<bool> shutdown;
    // Worker thread.
    std::thread worker_thread;
    // Exponentially smoothed accelerometer magnitude reading.
    std::atomic<double> current_reading;
    // Highest reading detected by accelerometer.
    std::atomic<double> highest_reading;
};

} // earthquake_detection_unit

accelerometer.cc:

namespace earthquake_detection_unit {

Accelerometer::Accelerometer() {
    std::atomic<bool> shutdown(false);
    std::atomic<double> current_reading(0.0f);
    std::atomic<double> highest_reading(0.0f);

    // Activate accelerometer using I2C.
    ActivateAccelerometer();

    worker_thread = std::thread(&Accelerometer::Worker, this);
}

Accelerometer::~Accelerometer() {
    shutdown = true;
    worker_thread.join();
    // Shut down accelerometer via I2C.
    ShutDownAccelerometer();
}

Accelerometer::Vector::Vector(int16_t x_reading, int16_t y_reading, int16_t z_reading) {
    // Omitted: constructs Vector object containing accelerations and magnitude.
}

void Accelerometer::Worker() {
    while (!shutdown) {
        CollectReading();
        if (current_reading > highest_reading) {
            highest_reading.store(current_reading, std::memory_order_relaxed);
        }

        // Gather samples every 2 ms.
        std::this_thread::sleep_for(std::chrono::milliseconds(kSleepTime_ms));
    }
}

void Accelerometer::CollectReading() {
    // Omitted: collect accelerometer sample and store it in
    //          latest_vector_reading.
    Vector latest_vector_reading(x_reading, y_reading, z_reading);

    double latest_magnitude_reading = latest_vector_reading.magnitude;

    current_reading.store(kSmoothingFactor * latest_magnitude_reading  
                          (1.0f - kSmoothingFactor) * current_reading,
                          std::memory_order_relaxed);
}

} // earthquake_detection_unit

CodePudding user response:

Unless I'm mistaken your problem is your constructor

Accelerometer::Accelerometer() {
    std::atomic<bool> shutdown(false);
    std::atomic<double> current_reading(0.0f);
    std::atomic<double> highest_reading(0.0f);

    // Activate accelerometer using I2C.
    ActivateAccelerometer();

    worker_thread = std::thread(&Accelerometer::Worker, this);
}

In the above highest_reading is a local variable that hides the variable of the same name at class scope. You are initializing this local variable and leaving the class member uninitialized.

Try something like

Accelerometer::Accelerometer() : shutdown(false), current_reading(0.0), highest_reading(0.0) {
    // Activate accelerometer using I2C.
    ActivateAccelerometer();

    worker_thread = std::thread(&Accelerometer::Worker, this);
}

I'm using an initializer list, generally the preferred way of initializing class members.

  • Related