I was very surprized to see that in the version of Visual C++ that comes with VS2013 the data members of a newly created class seem to be automatically initialized to 0 or null depending on their type. This is new - and very useful! - behaviour in my experience. I have previously only used VC++ Version 4 when writing serious apps and way back in the middle 1990's the initial values were explicitly stated as being undefined/random.
Is this perhaps some helpful attribute of using the debug libraries, or is it possible to rely on null initialization all the time?
As requested, some example code - nothing very exciting I am afraid:
class CData
{
public:
CData();
CData(const CData ©);
~Data();
const CData& operator=(const CData ©);
//Accessors/Mutators follow...
private:
bool Initialize_Data();
//Just giving a couple of examples of data member sets.
char *input_script_name;
int size_input_script_name;
int size_input_script_name_buffer;
char *interpreter_name;
int size_interpreter_name;
int size_interpreter_name_buffer;
};
CData::CData()
{
Initialize_Data();
}
CData::~CData()
{
//Code to store relevent data in registry
//and then free dynamically allocated memory follows...
}
bool CData::Initialize_Data()
{
//Code to retrieve data from registry stored at end of last run follows
//along with routines to check bounds.
//
//At this point, without executing any further a breakpoint is triggered
//and on inspecting data members in a Watch on 'this' I find them
//to be already initialized to either 0 or null respectively.
}
...
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//Application entry point;
CData application_data; //and away it goes!
//Usual name mutex to prevent multiple instances and message loop follow...
}
As I said VERY basic and I am not illustrating all the code. However, at the point the breakpoint in 'Initialize_Data' is reached - which is immediately on creating the class and BEFORE anything else is executed - all the data members show up as either 0 or null in a Watch. Which is rather surprising!
This is just a coincidence. What you probably observe is that something clears a lot of memory just before your object is initialized, and then your object is placed in that zero-initialized memory. There is no guarantee that this will remain the case, nor will you be able to rely on this on other platforms/compilers. In Debug mode, Visual C++ actually tries to clear to a non-zero bit-pattern, for example.
If you want to zero initialize, you can use the C++ 11 non-static member initializers like this:
char *input_script_name = nullptr;
int size_input_script_name = 0;
int size_input_script_name_buffer = 0;
char *interpreter_name = nullptr;
int size_interpreter_name = 0;
int size_interpreter_name_buffer = 0;
I'm not sure if the current compilers optimize this to a memset if everything is set to 0, but this is the way to go if you have access to a C++11 compiler.
Update
Just checked with Clang 3.4, it does emit a memset if everything is set to 0. GCC initializes using registers, but I suspect that's because my small test case only had ~10 member variables.
Related
I'm getting errors in my code. The code compiles, but I'd still like to get rid of the warnings. I've looked on stackoverflow and google and clicked on the warnings which take me to the microsoft.com page, explaining each, but I don't see concrete examples of how to get rid of them.
Here's the C++ code and the warnings.
void WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv);
VOID main() noexcept
{
CONST SERVICE_TABLE_ENTRY ste[] = { {L"MyService", ServiceMain}, {NULL, NULL} };
//C26485 Expression 'ste': No array to pointer decay (bounds.3).
StartServiceCtrlDispatcherW(ste);
}
// C26429 Symbol 'lpszArgv' is never tested for nullness, it can be marked as not_null (f.23).
// C26461 The pointer argument 'lpszArgv' for function 'ServiceMain' can be marked as a pointer to const (con.3).
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
{
// C26481 Don't use pointer arithmetic. Use span instead (bounds.1).
ssh = RegisterServiceCtrlHandlerExW(lpszArgv[0], (LPHANDLER_FUNCTION_EX) Service_Ctrl, 0);
...
}
Any help is appreciated.
Those are not compiler warnings but a code analysis warnings (based on CppCoreGuidelines), which give hints on how to improve code to prevent common errors - like null pointer dereferences and out of bound reads/writes. Fixing them might require use of gsl library of tools : https://github.com/microsoft/GSL.
//C26485 Expression 'ste': No array to pointer decay (bounds.3).
StartServiceCtrlDispatcherW(ste);
this informs you about potentially dangerous call, this function does not take information about size of the array so it might potentially lead to reading outside buffer. Analyzer does not know that this function relies on last element to be null initialized. You could silence this warning by allocating memory for ste on heap and releasing after the StartServiceCtrlDispatcherW call, or even better by wrapping allocated memory inside std::unique_ptr or even storing entries in std::vector
https://learn.microsoft.com/en-us/cpp/code-quality/c26485?view=msvc-170
// C26429 Symbol 'lpszArgv' is never tested for nullness, it can be marked as not_null (f.23).
// C26461 The pointer argument 'lpszArgv' for function 'ServiceMain' can be marked as a pointer to const (con.3).
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
You should be able to fix this warning with gsl:
const auto args = gsl::span<LPWSTR>(lpszArgv, dwArgc);
then use args as if it was lpszArgv. For instructions on how to use gsl see here: https://github.com/Microsoft/GSL
According to documentation, ServiceMain should always be called with at least one element in lpszArgv:
...The first parameter contains the number of arguments being passed to the service in the second parameter. There will always be at least one argument. The second parameter is a pointer to an array of string pointers. The first item in the array is always the service name.
https://learn.microsoft.com/en-us/windows/win32/services/writing-a-servicemain-function
So it should be fine to suppress this warning with:
#pragma warning(suppress: 26429 26461)
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
or better:
[[gsl::suppress(f.23)]]
[[gsl::suppress(con.3)]]
VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
links to both warnings:
https://learn.microsoft.com/en-us/cpp/code-quality/c26429?view=msvc-170
https://learn.microsoft.com/en-us/cpp/code-quality/c26461?view=msvc-170
// C26481 Don't use pointer arithmetic. Use span instead (bounds.1).
ssh = RegisterServiceCtrlHandlerExW(lpszArgv[0], (LPHANDLER_FUNCTION_EX) Service_Ctrl, 0);
..
this will be fixed if you use gsl::span as shown above
I have been working on this simply hobbyist OS, and I have decided to add some C++ support. Here is the simple script I wrote. When I compile it, I get this message:
cp.o: In function `caller':
test.cpp:(.text+0x3a): undefined reference to `__stack_chk_fail'
Here is the script:
class CPP {
public:
int a;
void test(void);
};
void CPP::test(void) {
// Code here
}
int caller() {
CPP caller;
caller.test();
return CPP.a;
}
Try it like this.
class CPP {
public:
int a;
void test(void);
};
void CPP::test(void) {
CPP::a = 4;
}
int caller() {
CPP caller;
caller.test();
return caller.a;
}
int main(){
int called = caller();
std::cout << called << std::endl;
return 0;
}
It seems to me that the linker you are using can't find the library containing a security function crashing the program upon detecting stack smashing. (It may be that the compiler doesn't include the function declaration for some reason? I am not familiar who actually defies this specific function.) Try compiling with -fno-stack-protector or equivalent.
What is the compiler used? A workaround might be defining the function as something like exit(1); or similar. That would produce the intended effect yet fix the problem for now.
I created a test program to show how this actually plays out. Test program:
int main(){
int a[50]; // To have the compiler manage the stack
return 0;
}
With only -O0 as the flag ghidra decompiles this to:
undefined8 main(void){
long in_FS_OFFSET;
if (*(long *)(in_FS_OFFSET + 0x28) != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
With -fno-stack-protector:
undefined8 main(void){
return 0;
}
The array was thrown out by ghidra in decompilation, but we see that the stack protection is missing if you use the flag. There are also some messed up parts of this in ghidra (e.g. int->undefined8), but this is standard in decompilation.
Consequences of using the flag
Compiling without stack protection is not good per se, but it shouldn't affect you in much. If you write some code (that the compiler shouts you about) you can create a buffer overflowable program, which should not be that big of an issue in my optinion.
Alternative
Alternatively have a look at this. They are talking about embedded systems, but the topic seems appropriate.
Why is the code there
Look up stack smashing, but to my knowledge I will try to explain. When the program enters a function (main in this case) it stores the location of the next instruction in the stack.
If you write an OS you probably know what the stack is, but for completeness: The stack is just some memory onto which you can push and off which you can pop data. You always pop the last pushed thing off the stack. C++ and other languages also use the stack as a way to store local variables. The stack is at the end of memory and when you push something, the new thing will be further forward rather than back, it fills up 'backwards'.
You can initialise buffers as a local variable e.g. char[20]. If you filled the buffer without checking the length you might overfill this, and overwrite things in the stack other than the buffer. The return address of the next instruction is in the stack as well. So if we have a program like this:
int test(){
int a;
char buffer[20];
int c;
// someCode;
}
Then the stack will look something like this at someCode:
[ Unused space, c, buffer[0], buffer[1] ..., buffer[19], a, Return Address, variables of calling function ]
Now if I filled the buffer without checking the length I can overwrite a (which is a problem as I can modify how the program runs) or even the return address (which is a major flaw as I might be able to execute malicious shellcode, by injecting it into the buffer). To avoid this compilers insert a 'stack cookie' between a and the return address. If that variable is changed then the program should terminate before calling return, and that is what __stack_chk_fail() is for. It seems that it is defined in some library as well so you might not be able use this, despite technically the compiler being the one that uses this.
I have some small helper functions needed throughout the code.
To work, they need to be initialized with some data once.
Where should I store the init data?
I've come up with two methods:
I create static variables in the scope of the helper.cpp file which I set with a dedicated setter function and then use in my helper function.
static int _initData = 0;
void initHelpMe(int initData)
{
_initData = initData;
}
void helpMe()
{
doSomethingWith(_initData);
}
Or I use a static function variable inside the original helper function and a default parameter to it.
void helpMe(int initData = 0)
{
static int _initData = 0;
if (initData != 0)
_initData = initData;
doSomethingWith(_initData);
}
(Lets asume that 0 is outside of the valid data range of initData and that I've not shown additional code to ensure an error is raised when the function is called for the first time without initiating it first.)
What are the advantages / disadvantages of those two methods and is there an even better way of doing it?
I of course like the second method, because it keeps all the functionality in one place. But I already know it is not thread-safe (which is not an issue a.t.m.).
And, to make this more interesting, albeit being C++ this is not to be used in object-oriented but in procedural code. So please no answers proposing objects or classes. Just imagine it to be C with the syntax of C++.
I was going to suggest that you wrap your data into an object, until I realized that you are asking for a C solution with a C++ tag...
Both of your solutions have their benefits.
The second one is the one I'd prefer, assuming we just go by "what it looks like/maintainability". However, there is a drawback if helpMe is called MANY times with initData == 0, because of the extra if, which isn't present in the first case. This may or may not be an issue if doSomethingWith() is long enough a function and/or the compiler has the ability to inline helpMe (and initData is constant).
And of course, something in the code will have to call initHelpMe too, so it may turn out to be the same anyway.
In summary: Prefer the second one, based on isolation/encapsulation.
I clearly prefer the second! Global static data in different compilation units are initialized in unspecified order (In one unit in order, though). Local static data of a function is initialized at first call.
Example:
If you have two translation units A and B. The unit A calls during initialization the function helpMe of unit B. Assume the order of initialization is A, B.
The first solution will set the zero initialized _initData to some initData. After that the initialization of unit B resets _initData back to zero and may produce a memory leak or other harm.
There is a third solution:
void helpMe(int initData = 0)
{
static std::once_flag once;
static int _initData = 0;
std::call_once(once, [&] {
_initData = initData;
}
doSomethingWith(_initData);
}
I feel strongly both ways.
Prefer option 2 for the isolation, but option 1 lends itself to porting to a C++ class. I've coded both ways. It comes down to the SW architecture.
Let me offer another point.
Both options down side: You have not limited initialization to one occurrence. "need to be initialized with some data once". It appears OP's conditions insure a proper initialization of initHelpMe(123) or HelpMe(123) followed by helpMe(), but do not prevent/detect a secondary initialization.
Should a secondary need to be prevented/detected, some additional code could be used.
// Initialization
if (_initData != 0) {
; // Handle error
}
_initData = initData;
Another paradigm I've used follows. It may not be realizable in you code as it does not pass initData as a parameter but magically can get it.
void helpMe(void) {
static int Initialized = 0;
if (!Initialized) {
Initialized = 1;
_initData = initData();
}
doSomethingWith(_initData);
}
I'm building a simple generic engine for my true start in the making of games, and I am trying to be somehow organized and decent in the making of my engine, meaning I don't want it to be something I throw to the side once I make what I'm planning to.
I add objects to be displayed, drawObjects, and these can either move, not move, and have an animation, or not have one.
In case they DO have an animation, I want to initialize a single animationSet, and this animationSet will have xxx animationComp inside of it. As I'm trying to be neat and have worked abit on "optimizations" towards memory and cpu usage (such as sharing already-loaded image pointers, and whatever came across my mind), I wanted to not ask for possibly unused memory in arrays.
So I had animationSetS* animationSet = NULL; initially, planning to do a animationSet = animationSetS[spacesINEED]; after, only on the objects that needed animation that I added, being those that aren't animations a NULL and therefore not using memory (correct?).
And then this question popped up! (title)
struct animationComp {
SDL_Rect* clip;
int clipsize;
};
struct animationSetS {
animationComp* animation;
int currentFrame;
int currentAnimation;
int animationNumber;
};
struct drawObject { // Um objecto.
char* name;
SDL_Surface* surface;
bool draw = true;
float xPos;
float yPos;
bool willMove = false; // 0 - Won't move, 10 - Moves alot, TO IMPLEMENT
bool isSprite = false;
animationSetS* animationSet;
};
I dabble alot in my questions, sorry for that. For any clarifications reply here, I'll reply within 10 minutes for the next... 1 hour perhaps? Or more.
Thanks!
Setting the pointer to NULL means that you'll be able to add ASSERT(ptr != NULL); and KNOW that your pointer does not accidentally contain some rubbish value from whatever happens to be in the memory it was using.
So, if for some reason, you end up using the object before it's been properly set up, you can detect it.
It also helps if you sometimes don't use a field, you can still call delete stuff; [assuming it's allocated in the first place].
Note that leaving a variable uninitialized means that it can have ANY value within it's valid range [and for some types, outside the valid range - e.g. pointers and floating point values can be "values that are not allowed by the processor"]. This means that it's impossible to "tell" within the code if it has been initialized or not - but things will go horribly wrong if you don't initialize things!
If this should be really implemented in C++ (as you write), why don't you use the C++ Standard Library? Like
struct animationSetS {
std::vector< std::shared_ptr<animationComp> > animation;
// ...
}
I have a very simple class that looks as follows:
class CHeader
{
public:
CHeader();
~CHeader();
void SetCommand( const unsigned char cmd );
void SetFlag( const unsigned char flag );
public:
unsigned char iHeader[32];
};
void CHeader::SetCommand( const unsigned char cmd )
{
iHeader[0] = cmd;
}
void CHeader::SetFlag( const unsigned char flag )
{
iHeader[1] = flag;
}
Then, I have a method which takes a pointer to CHeader as input and looks
as follows:
void updateHeader(CHeader *Hdr)
{
unsigned char cmd = 'A';
unsigned char flag = 'B';
Hdr->SetCommand(cmd);
Hdr->SetFlag(flag);
...
}
Basically, this method simply sets some array values to a certain value.
Afterwards, I create then a pointer to an object of class CHeader and pass it to
the updateHeader function:
CHeader* hdr = new CHeader();
updateHeader(hdr);
In doing this, the program crashes as soon as it executes the Hdr->SetCommand(cmd)
line. Anyone sees the problem, any input would be really appreciated
When you run into a crash, act like a crime investigator: investigate the crime scene.
what is the information you get from your environment (access violation? any debug messages? what does the memory at *Hdr look like? ...)
Is the passed-in Hdr pointer valid?
Then use logical deduction, e.g.:
the dereferencing of Hdr causes an access violation
=> passed in Hdr points to invalid memory
=> either memory wasn't valid to start with (wrong pointer passed in), or memory was invalidated (object was deleted before passing in the pointer, or someone painted over the memory)
...
It's probably SEGFAULTing. Check the pointers.
After
your adding some source code
your comment that the thing runs on another machine
the fact that you use the term 'flag' and 'cmd' and some very small datatypes
making me assume the target machine is quite limited in capacity, I suggest testing the result of the new CHeader for validity: if the system runs out of resources, the resulting pointer will not refer to valid memory.
There is nothing wrong with the code you've provided.
Are you sure the pointer you've created is the same same address once you enter the 'updateHeader' function? Just to be sure, after new() note the address, fill the memory, sizeof(CHeader), with something you know is unique like 0XDEAD, then trace into the updateHeader function, making sure everything is equal.
Other than that, I wonder if it is an alignment issues. I know you're using 8 bit values, but try changing your array to unsigned ints or longs and see if you get the same issue. What architecture are you running this on?
Your code looks fine. The only potential issue I can see is that you have declared a CHeader constructor and destructor in your class, but do not show the implementation of either. I guess you have just omitted to show these, else the linker should have complained (if I duplicate this project in VC++6 it comes up with an 'unresolved external' error for the constructor. It should also have shown the same error for the destructor if you had a... delete hdr; ...statement in your code).
But it is actually not necessary to have an implementation for every method declared in a class unless the methods are actually going to get called (any unimplemented methods are simply ignored by the compiler/linker if never called). Of course, in the case of an object one of the constructor(s) has to be called when the object is instantiated - which is the reason the compiler will create a default constructor for you if you omit to add any constructors to your class. But it will be a serious error for your compiler to compile/link the above code without the implementation of your declared constructor, so I will really be surprised if this is the reason for your problem.
But the symptoms you describe definitely sounds like the 'hdr' pointer you are passing to the updateHeader function is invalid. The reason being that the 1st time you are dereferencing this pointer after the updateHeader function call is in the... Hdr->SetCommand(cmd); ...call (which you say crashes).
I can only think of 2 possible scenarios for this invalid pointer:
a.) You have some problem with your heap and the allocation of memory with the 'new' operator failed on creation of the 'hdr' object. Maybe you have insufficient heap space. On some embedded environments you may also need to provide 'custom' versions of the 'new' and 'delete' operator. The easiest way to check this (and you should always do) is to check the validity of the pointer after the allocation:
CHeader* hdr = new CHeader();
if(hdr) {
updateHeader(hdr);
}
else
//handle or throw exception...
The normal behaviour when 'new' fails should actually be to throw an exception - so the following code will cater for that as well:
try{
CHeader* hdr = new CHeader();
} catch(...) {
//handle or throw specific exception i.e. AfxThrowMemoryException() for MFC
}
if(hdr) {
updateHeader(hdr);
}
else
//handle or throw exception...
}
b.) You are using some older (possibly 16 bit and/or embedded) environment, where you may need to use a FAR pointer (which includes the SEGMENT address) for objects created on the heap.
I suspect that you will need to provide more details of your environment plus compiler to get any useful feedback on this problem.