I have several configuration flags that I am implementing as structs. I create an object. I call a method of the object with a flag, which eventually triggers a comparison between two flags. However, by this time, one of the flags has been overwritten somehow.
To clarify, here's a VERY simplified version of the code that should illustrate what I'm seeing:
class flag_type { unsigned int flag; /*more stuff*/ };
flag_type FLAG1
flag_type FLAG2
class MyObject {
public:
void method1(const flag_type& flag_arg) {
//conditionals, and then:
const flag_type flag_args[2] = {flag_arg,flag_arg};
method2(flag_args);
}
void method2(const flag_type flag_args[2]) {
//conditionals, and then:
method3(flag_args[0]);
}
void method3(const flag_type& flag_arg) { //Actually in a superclass
//stuff
if (flag_arg==FLAG1) { /*stuff*/ }
//stuff
}
};
int main(int argc, const char* argv[]) {
//In some functions called by main:
MyObject* obj = new MyObject();
//Later in some other functions:
obj->method1(FLAG1);
}
With a debugger and print statements, I can confirm that both FLAG1 and flag_arg/flag_args are fine in both "method1" and "method2". However, when I get to method3, "FLAG1.flag" has been corrupted, so the comparison fails.
Now, although I'm usually stellar about not doing it, and it passes MSVC's static code analysis on strictest settings, this to me looks like the behavior of a buffer overrun.
I haven't found any such error by looking, but of course one usually doesn't. My question isA: Am I screwing up somewhere else? I realize I'm not sharing any real code, but am I missing something already? This scheme worked before before I rewrote a large portion of the code.
B: Is there an easier way than picking through the code more carefully until I find it? The code is cross-platform, so I'm already setting it up to check with Valgrind on an Ubuntu box.
Thanks to those who tried to help. Though, it should be noted that the code was for clarification purposes only; I typed it from scratch to show generally was was happening; not to compile. In retrospect, I realize it wasn't fair to ask people to solve it on so little information--though my actual question "Is there an easier way than picking through the code more carefully" didn't really concern actually solving the problem--just how to approach it.
As to this question, on Ubuntu Linux, I got "stack smashing" which told me more or less where the problem occurred. Interestingly, the traceback for stack smashing was the most helpful. Long story short, it was an embarrassingly basic error; strcpy was overflowing (in the operators for ~, | and &, the flags have a debug string set this way). At least it wasn't me who wrote that code. Always use strncpy, people :P
Related
Similar questions have been asked before, such as String literal matches bool overload instead of std::string.
But what I want to know is what should C++ developers do to prevent this from happening? As someone who writes C++ libraries for others to consume, what should I do to ensure this doesn't happen? Here is the example I ran into today, where a library had 2 initialize() methods:
void initialize(bool someflag) { /* ... */ }
void initialize(const std::string & name) { /* ... */ }
Now the problematic code was in the application that wanted to utilize this functionality and which called it in a manner similar to this:
initialize("robert");
At first glance you'd think that this would call initialize(string) but it actually calls the first initialize(bool) with a boolean flag set to true!
Yes, I know it can be fixed with this:
initialize( std::string("robert") );
But this puts the onus on the caller.
Edit for #zdan: I didn't consider the "solutions" in the other linked question to be great solutions since 1) I was hoping not to have to add a const char * version of every method that takes a bool or string, and 2) the template solution increases the maintainability of the code significantly for affected methods, renders them almost unreadable.
what should I do to ensure this doesn't happen?
One possibility is to create an overload that accepts a char const* and make it a pass through to the overload that accepts a std::string.
void initialize(char const* name) { initialize(std::string(name)); }
I'm using /NODEFAULTLIB to disable CRT(C Runtime), however my constructor is not called, which ends up causing an error in std::map (Access violation) because it is not initialized properly, since std::map constructor it's not called.
Code compiled with LLVM 8.0.0, compiled in mode debug x86
class c_test
{
public:
c_test( int a ) // Constructor not called
{
printf( "Test: %i\n", a ); // Doesn't appear and breakpoint is not reached
}
void add( const std::string& key, const std::string& val )
{
_data[ key ] = val;
}
private:
std::map< std::string, std::string > _data;
};
c_test test{ 1337 };
int main()
{
test.add( "qwrqrqr", "23142421" );
test.add( "awrqw", "12asa1faf" );
return 1;
}
I've implemented my own functions new(HeapAlloc), delete(HeapFree), printf, memcpy, memmove, etc, and all are working perfectly, I have no idea why this happening.
Disabling the CRT is madness.
This performs crucial functions, such as static initialisation. Lack of static initialisation is why your map is in a crippled state. I would also wholly expect various parts of the standard library to just stop working; you're really creating a massive problem for yourself.
Don't reinvent little pieces of critical machinery — turn the CRT back on and use the code the experts wrote. There is really nothing of relative value to gain by turning it off.
I discovered the problem and solved, one guy from another forum said that I needed manually call constructors that are stored in pointers in .CRT section, I just did it and it worked perfectly
I just called _GLOBAL__sub_I_main_cpp function that calls my constructor and solved all my problems, thanks for the answers.
I mean a scenario like this: There is some class (I call it victim) with a private data member and another class (named attacker) with some method, which, of course, normally does not have access to private members of other classes and does not even hold a reference to an instance of victim:
extern "C" {
#include <pigpiod_if2.h>
}
class victim {
private:
static bool is_ready;
static bool is_on;
public:
static void init ()
{
is_ready = true;
is_on = true;
}
/* Some other public methods go here. */
}
class attacker {
private:
static int last_read_pin;
public:
static void run ()
{
while (true) {
/* Some sensible code goes here. */
last_read_pin = -1;
time_sleep (0.01); // Using nanosleep () does not change behavior.
}
}
}
This is just a code snippet to illustrate the following question: Is it possible, not just in theory, but also practically, that attacker::run () can modify the values of the two private static vars of victim unintentionally, without addressing any public member of victim, maybe due to undefined behavior or even a compiler bug? Thank you.
UPDATE: After a hint from another user, I did rebuild the complete app using make clean and make. Also, I added the endless loop into my example. The change in is_ready occurs during the sixth run of the loop. Changing the sleep interval does not change behavior, though.
UPDATE #2: I ran my code through gdb with a watch on the is_ready variable, and I got an alert when last_read_pin was set to –1:
Hardware watchpoint 1: is_ready
Old value = true
New value = false
attacker::Run ()
last_read_pin = -1;
UPDATE #3: Moving last_read_pin into the Run () method itself, thereby making it an internal variable, does not help either.
UPDATE #4: After simply commenting out the line of code, which makes so much trouble, the issue still persisten, apparently being caused by one line above, which reads like this:
keypad::last_levels [h] [k] = 0;
I had to comment out this line, too, to get rid of the problem with is_ready being changed.
Could the use of pigpiod cause this issue? I an earlier version, I was using pigpio directly and did not encounter this problem.
Compiled with gcc 4.9.2.
After floating around the code line in question, I found out that the blunder was lying in the line before, which reads as follows:
last_levels [h] [l] = 0;
Unfortunately, h can be < 0. In this case, some kinda exception (array index out of bounds) should be thrown, but unfortunately, it isn't (Does anybody know why?). The gdb gave me the wrong information of the overwrite of is_ready to happen in the following line (Is this maybe a bug?), and I believed this without any criticism. As if this wasn't enough, this error made no problems until I changed my code in a completely different place!
This blunder has cost me quite much time, but now, at last, I know what its cause was, and I corrected it successfully. Thank you anyway for your hints and comments!
Tried to simplify the situation as much as possible. So I have a class:
class C
{
int * field;
public:
C() : field(nullptr) {}
void init(int* f) { field = f; }
int getI1() { return *field; }
int getI2() { return *field; }
};
which generates 2 Lint warnings 613 (Possible use of null pointer 'C::i'...)
I know that "field" won't be null when getI1() or getI2() are called. And unfortunately I cannot initialize it in constructor. So I want to suppress Lint warnings. I can do it like this
class C
{
int * field;
public:
C() : field(nullptr) {}
void init(int* f) { field = f; }
int getI1() { return *field; } //lint !e613
int getI2() { return *field; } //lint !e613
};
but in my real case:
1) There are rather many such classes and each class has many
functions that use this pointer.
2) My managements doesn't allow me to add too many lint
comments in the code.
So my question: does anyone know a command-line option that will let me tell Lint "I know the code is not best, just stop checking this particular member variable for null"?
Something similar to -sem parameter, maybe?
So my question: does anyone know a command-line option that will let me tell Lint "I know the code is not best, just stop checking this particular member variable for null"?
That's the wrong way to handle it (even if I knew such command line parameter).
PC-Lint warns you correctly about that
int getI1() { return *i; } //lint !e613
int getI2() { return *i; } //lint !e613
may unintentionally dereference a nullptr.
Just trying to suppress1 that waning isn't a very good idea, since the call of the init() function isn't mandatory.
The correct way to get rid of it is to add an explicit check like
int getI1() {
if(i) {
return *i;
}
throw std::runtime_error("i wasn't initialized properly.");
}
1) There are rather many such classes and each class has many functions that use this pointer.
There's no other way than just wading through them and refactor that bad code.
2) My managements doesn't allow me to add too many lint comments in the code.
That's a good policy. They spent the money to install the SCA tool for reasons, and want the code being improved.
If that collides with the time you've got available doing so, ask them to establish a task that allows you to accomplish that.
If you just want to concentrate on other (more important stuff) reported by PC-Lint, use grep or alike tools to filter out what you don't want to see ATM. But don't establish a command line parameters to suppress them completely. That are things that will be forgotten forever and never be touched or approached at later stages again.
1
Suppressing any errors or warnings given by a SCA tool like PC-Lint defeats the whole purpose of it, unless you're absolutely sure the tool gives you a false positive. Otherwise your company could simply save the money spent for the licenses, and stick to the bad coding habits.
It seems that after the constructor has run, you have an instance that is not usable (will crash if you call getT1() or getT2()). That's not something that I like at all.
Much better to have a constructor C(int* f). Problem goes away. This is a case where the warning is entirely justified and warns you of bad code, so the bad code should be fixed.
I know that code is bad, should be fixed and so on. Unfortunately I cannot do it right now (because of huge amount of effort for one person and highly risky changes), but those errors were overwhelming other, sometimes more critical, problems
I found out that to suppress this warning in one line you can do:
-esym(613, C::field)
Question is in bold below :
This works fine:
void process_batch(
string_vector & v
)
{
training_entry te;
entry_vector sv;
assert(sv.size() == 0);
...
}
However, this causes the assert to fail :
void process_batch(
string_vector & v
)
{
entry_vector sv;
training_entry te;
assert(sv.size() == 0);
...
}
Now I know this issue isn't shrink wrapped, so I'll restrict my question to this: what conditions could cause such a problem ? Specifically: variable initialization getting damaged dependant on appearance order in the stack frame. There are no malloc's or free's in my code, and no unsafe functions like strcpy, memcpy etc... it's modern c++. Compilers used: gcc and clang.
For brevity here are the type's
struct line_string
{
boost::uint32_t line_no;
std::string line;
};
typedef std::vector<boost::uint32_t> line_vector;
typedef std::vector<line_vector> entry_vector;
typedef std::vector<line_string> string_vector;
struct training_body
{
boost::uint32_t url_id;
bool relevant;
};
struct training_entry
{
boost::uint32_t session_id;
boost::uint32_t region_id;
std::vector< training_body> urls;
};
p.s., I am in no way saying that there is a issue in the compiler, it's probably my code. But since I am templatizing some code I wrote a long time ago, the issue has me completely stumped, I don't know where to look to find the problem.
edit
followed nim's suggestion and went through the following loop
shrink wrap the code to what I have shown here, compile and test, no problem.
#if 0 #endif to shrink wrap the main program.
remove headers till it compiles in shrink wrapped form.
remove library links till compiles in shrink wrapped form.
Solution: removing link to protocol buffers gets rid of the problem
The C++ standard guarantees that the following assertion will succeed:
std::vector<anything> Default;
//in your case anything is line_vector and Default is sv
assert(Default.size() == 0);
So, either you're not telling the whole story or you have a broken STL implementation.
OR: You have undefined behavior in your code. The C++ standard gives no guarantees about the behavior of a program which has a construct leading to UB, even prior to reaching that construct.
The usual case for this when one of the created objects writes beyond
its end in the constructor. And the most frequent reason this happens
in code I've seen is that object files have been compiled with different
versions of the header; e.g. at some point in time, you added (or
removed) a data member of one of the classes, and didn't recompile all
of the files which use it.
What might cause the sort of problem you see is a user-defined type with a misbehaving constructor;
class BrokenType {
public:
int i;
BrokenType() { this[1].i = 9999; } // Bug!
};
void process_batch(
string_vector & v
)
{
training_entry te;
BrokenType b; // bug in BrokenType shows up as assert fail in std::vector
entry_vector sv;
assert(sv.size() < 100);
...
}
Do you have the right version of the Boost libaries suited for your platform? (64 bit/32 bit)? I'm asking since the entry_vector object seems to be have a couple of member variables of type boost::uint32_t. I'm not sure what could be the behaviour if your executable is built for one platform and the boost library loaded is of another platform.