I am trying to access one of my MFC view's dialog elements. To do this, I run the following line of code:
((CButton*)GetDlgItem( IDC_RADIO_VIEW2 ))->SetCheck( 0 );
This causes the following exception:
Exception thrown at 0x53072844 (mfc140ud.dll) in NameOfMyApplication.exe: 0xC0000005: Access violation reading location 0x00000020.
What's strange about this is that the line above it does not cause an access violation, despite being basically the same thing. The line above it is:
((CButton*)GetDlgItem( IDC_RADIO_VIEW1 ))->SetCheck( 1 );
Does anyone know why this is happening?
Obviously, the item with the ID IDC_RADIO_VIEW1 exists, but the item with the ID IDC_RADIO_VIEW2 does not exist. So when you try to retrieve that dialog item, you get a NULL pointer. Yet you cast it to a CButton pointer and then attempt to dereference it without validating the pointer. Right there, you've invoked undefined behavior. Your program has a serious bug, and anything could happen. Luckily, the runtime environment jumped in and issued an access violation before the nasal demons could be unleashed.
The correct way to write the code would be to validate functions' return values. If nothing else, use an assertion:
CButton* pBtn = ((CButton*)GetDlgItem(IDC_RADIO_VIEW2));
ASSERT(pBtn != NULL);
pBtn->SetCheck(0);
This would have given you a very readable (and debuggable) error message.
Note that it would also be more readable to use symbolic constants, rather than magic numbers. So you should be writing SetCheck(BST_UNCHECKED) (or BST CHECKED or BST_INDETERMINATE).
There is no control with ID IDC_RADIO_VIEW2 as an immediate child of the dialog where you are calling the code.
The line of code that doesn't fail references a control with ID IDC_RADIO_VIEW1. It stands to reason, that the dialog has an immediate child window with ID IDC_RADIO_VIEW1.
I'm sure, that calling ((CButton*)GetDlgItem( IDC_RADIO_VIEW999 ))->SetCheck( 1 ); will exhibit a totally different error, although being "basically the same thing". You really need to learn, how computers work. Code doesn't work because it is similar to other working code (for some definition of "similar").
Related
I'm having problems with locating the address from which a error occurred, my whole code is running inside of a "try" statement and sadly whenever something is wrong I need to find the error using the old try and fail method by deleting parts of my code. Is there a better way to do it?
My current code:
try
{
do
{
if (somefunction)
if (somefunction2)
if (somefunction3)
if (somefunction4)
}
while (false);
}
catch (...)
{
// todo: somehow get the address where the error occurred
Logger::Log("Exception\n");
}
A simple solution to find out where an exception comes from is to use a unique message within each function. Catch the exception object and print the message. Or perhaps use even a different type of exception which will allow you to efficiently handle each case differently if that's what you want to do.
As for getting an "address", the trace of function calls that lead to the current point of execution is called a stacktrace (or backtrace). The stacktrace would contain information such as addresses. Theres no standard way to get a stacktrace yet, although it has been proposed for C++23.
However, once you've caught the exception, the stack will have been "unwound" such that you can't know where the exception came from. What you could do, is get the stack trace in the code that may be throwing (each of them since you don't know which one is the thrower) and store the trace in the exception. A central place to do that would be within the constructor of a custom exception type. This pattern is common in standard exception handling of modern languages.
Lastly, you don't necessarily need to make any changes to the program, if you instead run the program in a debugger and break on a throw, you can get all the information you can possibly get.
In a Java application, I use JNI to call several C++ methods. One of the methods creates an object that has to persist after the method finished and that is used in other method calls. To this end, I create a pointer of the object, which I return to Java as a reference for later access (note: the Java class implements Closable and in the close method, I call a method to delete the object).
However, in rare cases, approximately after 50.000 calls, the C++ code throws a segmentation fault. Based on the content of the log file, only a few lines of code are suspicious to be the source of error (they between the last printed log message and the next one):
MyObject* handle = new MyObject(some_vector, shared_ptr1, shared_ptr2);
handles.insert(handle); // handles is a std::set
jlong handleId = (jlong) handle;
I'd like to know whether there is a possible issue here apart from the fact that I'm using old-style C pointers. Could multi-threading be a problem? Or could the pointer ID be truncated when converted to jlong?
I also want to note that from my previous experience, I'm aware that the log is only a rough indicator of where a segmentation fault occurred. It may as well have been occurred later in the code and the next log message was simply not printed yet. However, reproducing this error may take 1-2 days, so I'd like to check out whether these lines have a problem.
After removing my std::set from the code, the error did not occur anymore. Conclusion: std::set in multithreading must be protected to avoid unrecoverable crashes.
I think if null pointer passed in a function, just let it gp and we can find the root cause easily. But my teammate say we should avoid the gp times in production code, clients may be upset if application usually crash although the root cause may be covered in some null pointer protection.
Which method will you use when you need to validate the pointer is null?
HRESULT function(const int* pNumber)
{
{ POINTER CHECK for pNumber... }
...
}
Method 1 - Ignore the invalid case
if(pNumber)
{
int a = *pNumber;
}
No GP
Possible enter abnormal flow
Hard to find root cause
Method 2 - Assert pointer, warning in debug mode
assert(pNumber);
int a = *pNumber;
May GP in release mode
Never enter abnormal flow
Easy to find root cause
Method 3 - Leave debug message and return error code
if(!pNumber)
{
OutputDebugString(L"Error Null pointer in function.\n");
return E_POINTER;
}
No GP
Never enter abnormal flow inside the function. Client may enter abnormal flow out-side if he ignores E_POINTER returned
Silently hard to find root cause
Method 4 - Throw a logic_error exception - Let caller catch
if(!pNumber)
{
throw std::logic_error("Null pointer of pNumber in function");
};
No GP
Possible resource leak in code sequence without resource management(RAII) when stack is unwinding.
Never enter abnormal flow
Hard to find where the exception is throwed
If you dereference a nullptr, you enter the land of undefined behaviour. This means, your compiler isn't obliged to do anything sensible, so this should really be avoided. It may also decide that since it is illegal, it never happened, so it removes the corresponding code (and thereby optimizing it) and you have logic errors without hitting a general protection fault.
I personally prefer the assert-case if a nullptr is absolutely invalid, but in that case a reference might be more sensible anyway. I don't think there is a general policy, because it depends heavily on the surrounding logic.
Exception are a serious breach of contract, and this make sense if you have two modules which communicate via interface. Not so much for a static function local to a cpp unit to throw it. Think about accessing an array past the end. It also assume the other party will catch it.
None of the other are good enough alone.
assert(pNumber); alone is weak. there might be a behavior which is
specific to release mode and you will not catch it. Furthermore it is
limited to the range of inputs you have tested in debug (which is far
from all).
Ignore the invalid case as shown above is plugin your head in the
ground like an ostrich.
OutputDebugString is weaker than assert. You the dev will eventually let
things slide with error messages you will get used to so much you
will stop reading them.
So If I am not using exceptions I will use
assert(pNumber);
if(pNumber)
{
}
else
{
//Log with a logger which has different logging level to the level you seem fit
}
I priffer Method 2
assert(pNumber);
int a = *pNumber;
because, In debug mode you can easily identify where the assert failure occured. even in release mode It assures null value will not continue in to the function inside. User will not see any abnormal behaviors and application would work as normal.
When I attempt to access this specific pointer, the application crashes and shows a c0000005 access violation error.
How can I catch this error and keep it from closing the process as I would in C# with a try&catch block.
Or how could I check if the access is denied to that area of memory before I use it?
Example:
MyClass** a = (MyClass**)(0x12345678);
a[0]->b = 1;
I am accessing a table of pointers and setting the value of one of the members of the class.
This does work, but the issue is that "0x12345678" doesn't always have the classes loaded in that area. The address has a value, but it doesn't point to the correct area of memory and it doesn't hold the value 0.
Keep in mind, this is a DLL that is loaded into a application that I no longer have the source for.
So I'm trying to set the settings of the application dynamically.
You can use Structured Exception Handling to trap these sorts of errors. In particular, filter for EXCEPTION_ACCESS_VIOLATION.
Just make sure you know what you're doing when you swallow the exception: if your garbage address points to a guard page, you might see the behaviour described here.
Platform : Win32
Language : C++
I get an error if I leave the program running for a while (~10 min).
Unhandled exception at 0x10003fe2 in ImportTest.exe: 0xC0000005: Access violation reading location 0x003b1000.
I think it could be a memory leak but I don't know how to find that out.
Im also unable to 'free()' memory because it always causes (maybe i shouldn't be using free() on variables) :
Unhandled exception at 0x76e81f70 in ImportTest.exe: 0xC0000005: Access violation reading location 0x0fffffff.
at that stage the program isn't doing anything and it is just waiting for user input
dllHandle = LoadLibrary(L"miniFMOD.dll");
playSongPtr = (playSongT)GetProcAddress(dllHandle,"SongPlay");
loadSongPtr = (loadSongT)GetProcAddress(dllHandle,"SongLoadFromFile");
int songHandle = loadSongPtr("FILE_PATH");
// ... {just output , couldn't cause errors}
playSongPtr(songHandle);
getch(); // that is where it causes an error if i leave it running for a while
Edit 2:
playSongPtr(); causes the problem. but i don't know how to fix it
I think it's pretty clear that your program has a bug. If you don't know where to start looking, a useful technique is "divide and conquer".
Start with your program in a state where you can cause the exception to happen. Eliminate half your code, and try again. If the exception still happens, then you've got half as much code to look through. If the exception doesn't happen, then it might have been related to the code you just removed.
Repeat the above until you isolate the problem.
Update: You say "at that stage the program isn't doing anything" but clearly it is doing something (otherwise it wouldn't crash). Is your program a console mode program? If so, what function are you using to wait for user input? If not, then is it a GUI mode program? Have you opened a dialog box and are waiting for something to happen? Have you got any Windows timers running? Any threads?
Update 2: In light of the small snippet of code you posted, I'm pretty sure that if you try to remove the call to the playSongPtr(songHandle) function, then your problem is likely to go away. You will have to investigate what the requirements are for "miniFMOD.dll". For example, that DLL might assume that it's running in a GUI environment instead of a console program, and may do things that don't necessarily work in console mode. Also, in order to do anything in the background (including playing a song), that DLL probably needs to create a thread to periodically load the next bit of the song and queue it in the play buffer. You can check the number of threads being created by your program in Task Manager (or better, Process Explorer). If it's more than one, then there are other things going on that you aren't directly controlling.
The error tells you that memory is accessed which you have not allocated at the moment. It could be a pointer error like dereferencing NULL. Another possibility is that you use memory after you freed it.
The first step would be to check your code for NULL reference checks, i.e. make sure you have a valid pointer before you use it, and to check the lifecycle of all allocated and freed resources. Writing NULL's over references you just freed might help find the problem spot.
I doubt this particular problem is a memory leak; the problem is dereferencing a pointer that does not point to something useful. To check for a memory leak, watch your process in your operating system's process list tool (task manager, ps, whatever) and see if the "used memory" value keeps growing.
On calling free: You should call free() once and only once on the non-null values returned from malloc(), calloc() or strdup(). Calling free() less than once will lead to a memory leak. Calling free() more than once will lead to memory corruption.
You should get a stack trace to see what is going on when the process crashes. Based on my reading of the addresses involved you probably have a stack overflow or have an incorrect pointer calculation using a stack address (in C/C++ terms: an "auto" variable.) A stack trace will tell you how you got to the point where it crashed.