Monday, May 16, 2022

Dangers of C++

Recently I had a strange bug that caused a previously working C++ simulation to fail. It turned out that a logically unrelated portion of code was corrupting the memory and that corruption resulted in changing of parameter values which resulted in instability. Corruption was due to writing out of index. If that index pointed to a memory location outside the boundaries of my program I would get an access violation. Unfortunately, indices were pointing to my programs memory, therefore I did not get any errors from the operating system and had to pin point the bug by trial and error, i.e. commenting out sections of code until I got a stable state and then uncommenting until I got instability. A simplified version of the code:

#include <stdexcept>
void getDoubleVectorFromName(string name, double vec[MAX_FILE_NAME_LENGTH]) {
if (name.length() > MAX_FILE_NAME_LENGTH) { //Without this check, if string is unitialized, its length might be more than MAX_FILE_NAME_LENGTH, which might result in out of bounds writing below, leading to undefined behaviour.
char msg[255];
sprintf(msg, "ERROR in %s, %s: name.length() (%llu) > MAX_FILE_NAME_LENGTH (%d)\n", __FILE__, __FUNCTION__, name.length(), MAX_FILE_NAME_LENGTH);
printf(msg);
throw std::invalid_argument(msg);
}
for (size_t i = 0; i < name.length(); i++) {
if (name[i] < 0) {
char msg[255];
sprintf(msg, "ERROR in %s, %s: Not a valid name character code: %d at index %llu\n", __FILE__, __FUNCTION__, name[i], i);
printf(msg);
throw std::invalid_argument(msg);
}
vec[i] = name[i];
}
for (size_t i = name.length(); i < MAX_FILE_NAME_LENGTH; i++) {
vec[i] = 0;
}
}
view raw dangerous.cpp hosted with ❤ by GitHub

Friday, May 13, 2022

Simulink: Generating code without model version and date

When you generate code with Simulink, the generated header and source files will have model version and date in code comments. This results in version changes in your version control system even when you have not changed any logic. In order to avoid unnecessary version updates, you should comment out the "Model version" and "C/C++ source code generated on" sections in the ert_code_template.cgt file (Configuration Parameters > Code Generation > Templates > Code Templates).

Dangerous while loop

Today a program I am writing stopped responding. After some debugging effort, I came across a 3rd party function that limited an input angle to the [-180, 180] degrees interval. It was using a while loop to increment or decrement the angle. Unfortunately, I was passing an uninitialized variable to it and its value was -9.2...e+61. Such a large value would take years for the function to limit. Below is the original function constrainAngleWhile(), together with much better alternatives:

//Demonstrate different methods to limit an angle to the [-180, 180] degree interval.
//To quickly test, paste code to https://www.onlinegdb.com/online_c++_compiler
//Şamil Korkmaz, May 2022
#include <iostream>
#include <math.h>
using namespace std;
//https://stackoverflow.com/a/11498248/51358
double constrainAngleMod(double x) {
x = fmod(x + 180,360);
if (x < 0) x += 360;
return x - 180;
}
double constrainAngleWhile(double x) {
double limitedX = x;
//Note that the while loops below will take a long time if the input x is a large value.
//For example, an unitialized variable can have a value like -9.2...e+61 which would take years!
while (limitedX < -180) limitedX += 360;
while (limitedX > 180) limitedX -= 360;
return limitedX;
}
int main() {
cout << "Calculating...\n";
//Using remainder(): https://stackoverflow.com/a/11503585/51358
cout << remainder(180, 360) << ", " << constrainAngleWhile(180) << endl;
cout << remainder(181, 360) << ", " << constrainAngleWhile(181) << endl;
cout << remainder(-181, 360) << ", "<< constrainAngleWhile(-181) << endl;
cout << remainder(-359, 360) << ", "<< constrainAngleWhile(-359) << endl;
cout << remainder(359, 360) << ", "<< constrainAngleWhile(359) << endl;
cout << remainder(-360, 360) << ", "<< constrainAngleWhile(-360) << endl;
cout << remainder(360, 360) << ", "<< constrainAngleWhile(360) << endl;
double angle_deg = 1e12;
cout << remainder(angle_deg, 360) << ", " << constrainAngleMod(angle_deg) << endl;
cout << constrainAngleWhile(angle_deg) << endl;
cout << "Finished.\n";
return 0;
}
view raw limitAngle.cpp hosted with ❤ by GitHub