Debug runs properly and the Release version does not work properly.

Source: Internet
Author: User

Introduction if you encounter a common error during your development, your Release version may not run properly and the Debug version is running correctly, I recommend that you read this article: as you may imagine, the Release version ensures that your applications can run like the Debug version. If you have never performed a Release test after the development phase is complete or within a period of time during development, but you have found problems during the test, please refer to our debugging Rule 1: Rule 1: conduct regular debugging and Release testing on the development software. the longer the time interval for testing the Release version, the more difficult it is to eliminate the problem. At least one test is performed on the Release version every week, this allows you to save potential troubleshooting time in a compact development cycle. do not delete the Code required by the Release version. This seems obvious, but it is a mistake that developers often make accidentally, the reason is that the compiler will automatically exclude Macros in the code when compiling the Release version. For example, ASSERT and TRACE are automatically excluded in the Release version, the problem is that the code you run in these macros is also deleted, which is a very dangerous thing J, for example: ASSERT (m_ImageList.Create (MAKEINTRESOURCE (IDB_IMAGES), 16, 1, RGB (255,255,255); this type of code won't go wrong in Debug mode, and the image list is also automatically created. What about the Release version? Subsequent Use of the m_ImageList object will only cause the program Crash !, Therefore, we recommend that you use logical operators for verification in the ASSERT macro. Rule 2: Do not place the code in the place where it is executed only in a certain compilation option. The use of the code inside the compilation option macro such as _ DEBUG must not affect the use of the entire program. Rule 3: Do not use rule 2 as the criterion to delete the ASSERT macro. The ASSERT macro is a useful tool, but it is easy to use incorrectly. make the Debug compilation mode close to the Release mode. If the problem with your Release version is caused by the code automatically excluded by the compiler, your problem may be reproduced through this method. some problems may be caused by predefined symbols between different compilation options. Therefore, you can change the predefined symbols in the compilation mode so that your Debug mode is close to the Release mode, observe whether errors are generated. The method for changing the pre-defined symbols of compilation is as follows: .. alt-F7 open the Project Settings, on the C ++/C page, select the "General" category and change the "_ DEBUG" symbol to "NDEBUG ". B .. on the C ++/C page, select the "Preprocessor" type and add the pre-defined symbol "_ DEBUG" to the "Undefined Symbols" column. c .. use "Rebuild All" to re-compile. If the above settings are used The problems in the compilation mode are reproduced in the Debug mode. Follow these steps to modify your code: .. find out all important execution statements in ASSERT, or modify ASSERT to VERIFY. B .. check all the code in "# ifdef _ DEBUG" to exclude the code used in the Release mode. c .. find the TRACE to exclude all important execution statements. similar to ASSERT, TRACE is compiled only in Debug mode. if you corrected your problem in Debug mode through the above modification, you can re-compile the Release mode, which is very likely to solve the previous problem !. Incorrect assumptions cause compilation mode errors do you often assume that your variables or objects are initially converted into a specified value (maybe 0 )? Do you assume that all your associated resources exist in the application? These are also the causes of different problems in Debug and Release modes. Rule 4: Unless you initialize the variables in the Code, the above assumptions cannot be made. including global variables, automatic variables, application objects, and new objects. this problem often occurs in the memory sequence. Remember to compare the two struct objects using memcmp for ease of use when using the struct, which works normally in the Debug version, when the Release version calculates an incorrect solution, it does not seem that an incorrect assumption can be made! Rule 5: Make sure that all references to the deleted resource are deleted, for example, resource. h. in software development, the initialization of variables and memory is different for different compilation versions. if you assume that the variable Initialization is 0, an exception occurs in the Release mode of the Win9x system. Therefore, it is safer to explicitly clear 0 memory for all variables. if you reference a deleted resource, your Debug version works normally, but the Release version may crash. do you believe in the compiler? The compiler warning level has a considerable relationship with compilation noise. by increasing the compiler warning level, you can increase the chance of program hidden problem exposure. generally, the warning Level is set to "Level 3" or "Level 4 ". compile and resolve all warnings. This is a good suggestion for releasing the Release application. this exposes many initialization problems and other potential errors that may cause problems in your application. rule 6: Set the compilation warning Level to "Level 3" or "Level 4" before starting the project. Ensure that all warnings are cleared before registering the code !. Summary Report: Debugging in the compilation mode has been heard more than once. Some VC developers say that debugging cannot be performed in the Release mode. Fortunately, through corresponding settings, debugging can be performed in the Release mode, therefore, it is just an absurd saying that is just a rumor. Rule 7: Debug in Release mode when all current methods are invalid. the Release mode can be debugged. The first step is to open the symbol table: .. alt-F7 open the Project Settings, on the C ++/C page, select the "General" class, modify Debug Info setting to "Program Database ". B .. on the "Link" Page, select "Generate Debug Info ". c .. "Rebuild All" these settings allow you to retain the symbol table in Release mode. You can also consider the following settings: .. debug the Release version application. You can disable the optimization option. B .. if you cannot set a breakpoint in the Release mode, add the command "_ asm {int 3}" to stop your application in this row (confirm to exclude this code when publishing the application ). several restrictions on debugging in Release mode. a .. the biggest problem is that you cannot track the MFC function. The reason is that the dynamic link library of the Release version does not contain debugging information and symbol tables. B .. same as above. To debug the called dll, you must add the debugging information and symbol table to all of them. the compiler generated the error code? Sometimes you may find that the VC ++ compiler generates 'problematic Code', but frankly speaking, people usually complain too early. you can disable the optimization option in the Release mode for testing. if this operation solves your problem, there may be problems with your encoding habits. believe it or not, it is very likely that there is an ambiguous solution in your code or it seems to be correct. In some cases, it is also true. for example, the following code seems to be 'normal' In the Debug mode, but errors will occur in the Release mode! # Include int * func1 () {int retval = 5; return & retval;} int main (int argc, char * argv []) {printf ("% d/n ", * func1 (); return 0;} I believe that most programmers, especially beginners, are prone to such situations. Rule 8: If Optimization Options in the Release mode are disabled, your application can run normally, and activation of optimization options may cause problems, most of which are caused by your bad coding habits. this means you must carefully check your code and clear the incorrect assumptions, floating pointers, and so on. similarly, this tells you that in the Debug mode and the Release mode where optimization options are disabled, your application works normally because of the luck of the system. You must correct the hidden code, otherwise, it may cause huge losses in the future. Rule 9: If you have thoroughly checked your code and have not found any problems, you 'd better open the optimization option one by one to limit the cause of the error to a certain range. BTW-the above problem code is automatically detected by the C ++ compiler. if you have followed rule 6, you may have fixed these problems in the previous step. based on my development experience, the compiler rarely produces wrong code (of course, pay attention to the interface program boundary alignment problem ). generally, when using the template class, the VC6 compiler may produce an ASSERT error. In this case, you only need to update the patch to solve the problem. The final thinking requires a little more rigorous detection in daily coding to effectively avoid the emergence of the new Debug-v-Release mode. Here are some of my experiences. 1. check out the code to be modified. 2. modify the code to exclude all warnings and compile Debug and Release versions. 3. test the new code in detail, that is, after debugging the new code segment in one step, enter the work code to ensure that the Code is correct. 4. correct all problems. 5. check in the new code after confirmation ). 6. the new registration code is compiled to ensure that the new registration code is integrated with other codes. 7. test the code again. 8. to solve the problem, follow the above steps to solve a large number of problems in the design and development process, avoid new problems that are hard to locate when the application is finally released. note: This article describes some of my experiences with Release of the Release version application during my development process, and I am struggling to find some experience when I encounter errors. The original Article is from the codeproject, rewrite it into an article suitable for Chinese developers and hope it will be useful to everyone. Thank you! Reprinted: the Debug version includes debugging information, so it is much larger than the Release version (hundreds of KB to several Mb ). As to whether DLL support is required, we mainly look at the compilation options you use. If it is based on ATL, Debug and Release have similar requirements on DLL. If you use the dynamic MFC Library as the compilation option, you need to support MFC42D. DLL and other libraries. The Release version requires the support of MFC42.DLL. Release Build does not Debug the source code, regardless of the MFC diagnostic macro. It uses the MFC Release library to compile ten programs to optimize the application speed, while the Debug Build is the opposite, it allows debugging of source code, defines and uses the diagnostic macro of MFC, and uses the Debug library of MFC, which does not optimize the speed. I. essential differences between Debug and Release compilation methods Debug is usually called a Debug version, which contains debugging information without any optimization, so that programmers can Debug programs easily. Release is called a Release version. It is often optimized to optimize the code size and running speed, so that users can use it well. The real secret of Debug and Release lies in a set of compilation options. The options for the two are listed below (of course, there are other options, such as/Fd/Fo, but the difference is not important. Usually they will not cause the Release version error and will not be discussed here) debug version:/MDd/MLd or/MTd use the Debug runtime library (runtime function library of the DEBUG version)/Od to disable the optimization switch/D "_ DEBUG" is equivalent to # define _ Debug, enable the compile and debug code switch (mainly for the assert function)/ZI to create the Edit and continue database, in this way, if the source code is modified during the debugging process, you do not need to re-compile/GZ to help capture memory errors/enable the minimal re-link switch on Gm to reduce the link time. Release Version: /MD/ML or/MT use the release version of the runtime function library/O1 or/O2 optimization switch, minimal or fastest Program/D "NDEBUG" to turn off the Conditional compilation and debugging code switch (that is, do not compile asse) Rt function)/GF combines repeated strings and puts string constants in read-only memory to prevent modification. In fact, there is no essential limit between Debug and Release, they are just a set of compilation options, and the compiler only acts according to the predefined options. In fact, we can even modify these options to get optimized debugging versions or release versions with trace statements. Ii. Under what circumstances will the Release version go wrong with the above introduction, let's compare these options one by one to see how the Release version errors are produced 1. runtime Library: Specifies the Runtime function Library to be linked, which usually only affects the program performance. The Runtime Library of the debug version contains debugging information and uses some protection mechanisms to help identify errors. Therefore, the performance is inferior to that of the release version. The Runtime Library provided by the compiler is usually stable and does not cause Release errors. However, the Debug Runtime Library enhances error detection, such as heap memory allocation, sometimes there may be Debug errors but Release is normal. It should be pointed out that, if the Debug is wrong, even if the Release is normal, the program must have a Bug, but it may be that a certain run of the Release version is not shown. 2. Optimization: This is the main cause of errors, because the source program is basically translated directly when optimization is disabled, and the compiler will make a series of assumptions after optimization is enabled. These errors mainly include: (1) Frame Pointer (FPO): All call information (return address and parameter) during function calling) and automatic variables are placed in the stack. If the declaration and implementation of a function are different (parameters, return values, and call methods), an error occurs-but in Debug mode, stack access is implemented through the address saved by the EBP register, if no errors such as array out-of-bounds (or "not many" out-of-bounds) occur, the function can normally be executed. In the Release mode, optimization will omit the EBP stack base address pointer, in this way, accessing the stack through a global pointer will cause the program to crash if the returned address is incorrect. The strong type feature of C ++ can check the majority of such errors, but if forced type conversion is used, it will not work. You can force the/Oy-compilation option in the Release version to disable frame pointer omitting to determine whether such errors are possible. Common Errors include: ● An error occurred while writing the message response function of MFC. The correct value should be afx_msg LRESULT OnMessageOwn (WPARAM wparam, LPARAM lparam); ON_MESSAGE macro contains forced type conversion. One way to prevent this error is to redefine the ON_MESSAGE macro and add the following code to stdafx. h (in # include "afxwin. h "later), the compilation will report an error when the function is incorrect. # undef ON_MESSAGE # define ON_MESSAGE (message, memberFxn)/{message, 0, 0, 0, AfxSig_lwl,/(AFX_PMSG) (AFX_PMSGW) (static_cast <LRESULT (AFX_MSG_CALL/CWnd: *) (WPARAM, LPARAM)> (& memberFxn)}, (2) volatile variable: volatile tells the compiler that the variable may be modified by unknown methods (such as systems, other processes, and threads) outside the program ). To improve program performance, the optimizer usually places some variables in registers (similar to the register keyword), while other processes can only modify the memory where the variable is located, but the value in the register remains unchanged. If your program is multi-threaded, or you find that the value of a variable is inconsistent with the expected value and you are sure that the setting is correct, you may encounter such a problem. This type of error is sometimes manifested as the program has the fastest optimization error and the smallest optimization is normal. Add volatile to the variables you think are suspicious. (3) Variable Optimization: The optimization program optimizes the variables based on the usage of the variables. For example, a function has an unused variable. In the Debug version, it may mask an array out of bounds. In the Release version, this variable may be optimized, in this case, the array out-of-bounds will destroy the useful data in the stack. Of course, the actual situation is much more complicated than this. Related errors include: ● illegal access, including array out-of-bounds and pointer errors. For example, void fn (void) {int I; I = 1; int a [4]; {int j; j = 1;} a [-1] = 1; // Of course, the error is not so obvious. For example, the subscript is the variable a [4] = 1;} j, although it has a scope when the array is out of bounds, its space is not reclaimed, therefore, I and j will overwrite the border. The Release version may be optimized because I and j are not very useful, so that the stack is damaged. 3. _ DEBUG and NDEBUG: When _ DEBUG is defined, the assert () function is compiled, but NDEBUG is not compiled. In addition, there are a series of assertion Macros in VC ++. This includes: ansi c asserted void assert (int expression); C Runtime Lib asserted _ ASSERT (booleanExpression); _ ASSERTE (booleanExpression); MFC asserted ASSERT (booleanExpression ); VERIFY (booleanExpression); ASSERT_VALID (pObject); ASSERT_KINDOF (classname, pobject); ATL asserted ATLASSERT (booleanExpression); in addition, the compilation of the TRACE () macro is also controlled by _ DEBUG. All these assertions are compiled only in the Debug version, but are ignored in the Release version. The only exception is VERIFY (). In fact, these macros call the assert () function, but attach some library-related debugging code. If you add any program code to these macros, instead of a Boolean expression (for example, a value assignment or a function call that can change the value of a variable), the Release version will not perform these operations, this may cause errors. It is easy for beginners to make such mistakes, and the search method is also very simple, because these macros are listed above, you only need to use the Find in Files function of VC ++ to Find the place where these macros are used in all Files of the project and then check them one by one. In addition, some experts may also add Conditional compilation such as # ifdef _ DEBUG. Pay attention to it. By the way, it is worth mentioning that the VERIFY () macro allows you to put program code in a Boolean expression. This macro is usually used to check the return values of Windows APIs. Some people may abuse VERIFY () For this reason. In fact, this is dangerous because VERIFY () violates the idea of assertions and cannot completely separate program code from debugging code, in the end, it may cause a lot of trouble. Therefore, experts suggest using this macro as little as possible. 4./GZ option: This option will do the following (1) initialize memory and variables. Including using 0xCC to initialize all automatic variables, 0xCD (Cleared Data) to initialize memory allocated in the heap (that is, dynamically allocated memory, such as new), 0xDD (Dead Data) fill in the released heap memory (such as delete), 0xFD (deFencde Data), and initialize the protected memory (debug adds the protected memory before and after the dynamically allocated memory to prevent cross-border access ), the words in the brackets are the notes suggested by Microsoft. The advantage of doing so is that these values are very large and cannot be used as pointers (and in 32-bit systems, pointers are rarely odd values, in some systems, odd-number pointers produce runtime errors), which are rarely used as numerical values, and these values are easy to recognize, therefore, it is helpful to find the Release version errors. Note that many people think that the compiler will use 0 to initialize the variable, which is wrong (and this is not conducive to finding errors ). (2) When a function is called through the function pointer, the matching of the function call is verified by checking the stack pointer. (To prevent original form mismatch) (3) Check the stack pointer before returning the function and confirm that it has not been modified. (Avoid out-of-bounds access and original form mismatch. When combined with the second item, you can roughly simulate frame pointer omitting FPO.) The common/GZ option will cause errors in the Debug version and the Release version is normal, because uninitialized variables in the Release version are random, this may cause the pointer to point to a valid address and mask illegal access. In addition, options such as/Gm/GF have fewer errors, and their effects are obvious and easy to find. In the process of using VC to develop software, just when you want to enjoy the excitement, you suddenly find that the release and debug running results are inconsistent or even wrong, and release is not convenient for debugging, it is really a good deal, but it hurts, and the problem always needs to be solved. The following describes my two experiences to see if it is one of them: 1. variable. As we all know, the operations performed by debug and release when initializing variables are different. debug assigns each byte to 0xcc, the value assignment of release is similar to random (I think it is allocated directly from the memory and has not been initialized, but it is unknown why debug is not 0xff or 0x00 or something else ). This makes it clear that if a variable in your program is referenced when it is not initialized, it is likely that an exception occurs: using it as a control variable will lead to inconsistent process orientation; using it as an array subscript will cause the program to crash; it is more likely to cause other errors due to inaccuracy of other variables. So it is the easiest and most effective way to initialize a default value for a variable immediately after declaring it. Otherwise, there is no place to find it when the project is too large. Code errors may be ignored and not noticed in the debug mode. For example, in the debug mode, most arrays do not go out of bounds and are exposed in the release, this is difficult to find: (I suggest you pay more attention to it. 2. custom message parameters. MFC provides us with a good message mechanism and adds custom messages, so I don't need to talk about the benefits. Is there a problem with debug and release? The answer is yes. When declaring the function body of a custom message, you will often see the following statement: afx_msg LRESULT OnMessageOwn (); when you use message transmission among multiple threads or processes, it will lead to errors such as invalid handles. This is because the message body parameter is not added, that is, it should be written as: afx_msg LRESULT OnMessageOwn (WPARAM wparam, LPARAM lparam); (I am not quite clear about the specific reason, is it because the WPARAM + LPARAM space is allocated according to the default parameters during the call, which damages the application's memory space? Please give more tips) to avoid the following methods: 1. note the initialization of variable 2. standard syntax for custom messages 3. it is best to comment out the debugging statement TRACE and so on. 4. try-catch (...) differences between VERIFY and ASSERT: one can be executed under Release, the other cannot be DEBUG or RELEASE versions, and debugging problems: Memory Allocation Problem 1. the variable is not initialized. The following program runs well in debug. Thing * search (thing * something) BOOL found; for (int I = 0; I <whatever. getSize (); I ++) {if (whatever [I]-> field = something-> field) {/* found it */found = TRUE; break ;} /* found it */} if (found) return whatever [I]; else return NULL; but not in release, because in debug, found = FALSE is automatically initialized for the variable, but not in release. Initialize variables, classes, or structures as much as possible. 2. data overflow problems include: char buffer [10]; int counter; lstrcpy (buffer, "abcdefghik"); In debug, the buffer NULL overwrites the counter high, however, unless counter> 16 M, there is no problem. However, in the release version, counter may be placed in the register, so that NULL overwrites the space in the buffer, which may be the return address of the function, leading to access error. 3. The memory allocation methods for DEBUG and RELEASE versions are different. If you apply for 6 * sizeof (DWORD) = 24 bytes for ele in DEBUG, you are actually allocated 32 bytes (32bytes for debug ), in the release version, 24 bytes are allocated to you (8 bytes for the release version). Therefore, if you write ele [6] In the debug version, there may be no problems, in the release version, access violate exists. II. ASSERT and VERIFY 1. ASSERT will not be compiled in the Release version. ASSERT macro is defined in this way # ifdef _ DEBUG # define ASSERT (x) if (x) = 0) report_assert_failure () # else # define ASSERT (x) # endif is actually complicated, but it doesn't matter. If you add the Code required by the program in these statements, such as ASSERT (pNewObj = new CMyClass); pNewObj-> MyFunction (); in this case, pNewObj in the Release version is not allocated space. Therefore, when executing the next statement, the program reports that the program has performed illegal operations. In this case, use VERIFY: # ifdef _ DEBUG # define VERIFY (x) if (x) = 0) report_assert_failure () # else # define VERIFY (x) # In this case, the code can be executed in the release version. III. parameter problem: the custom message processing function must be defined as follows: afx_msg LRESULT OnMyMessage (WPARAM, LPARAM); The returned value must be HRESULT type; otherwise, Debug will pass, and Release will fail IV. memory Allocation ensures data creation and cleanup Uniformity: If a DLL provides a function that can create data, the DLL should also provide a function to destroy the data. Data creation and cleanup should be at the same level. V. DLL disasters people refer to the inconsistency image caused by DLL mixing of different versions as "DLL Hell", or even Microsoft itself ( http://msdn.microsoft.com/library/techart/dlldanger1.htm ). If your program uses your own DLL, note that: 1. You cannot mix the debug and release DLL versions. Both debug and release versions are release. The solution is to place the debug and release programs in the debug and release directories of the main program. 2. Never think that static Connection Library will solve the problem, which will only make the situation worse. Debug in VI. RELEASE Board: 1. Change ASSERT () to VERIFY (). Find the code defined in "# ifdef _ DEBUG". If you need the code in the RELEASE version, move it out of the definition. Find the code in TRACE (...) because the code is not compiled in RELEASE. Check whether the Code required in the RELEASE is not cheap. 2. The differences brought about by variable initialization exist in different systems or between DEBUG/RELEASE versions. Therefore, initialize the variables. 3. Is there a warning during compilation? Set the warning level to 3 or 4, and ensure that no warning appears during compilation. VII. change the optimization option under the "C ++/C" Project in Project Settings to Disbale (Debug ). Compiler Optimization may cause many unexpected errors. Please refer http://www.pgh.net/~newcomer/debug_release.htm 1. in addition, you can debug the software of the RELEASE version. Make the following changes: set "category" to "General" under "Project Settings" C ++/C "and" Debug Info "to" Program Database ". Select the "Generate Debug Info" check box under the "Link" project. "Rebuild All" has some restrictions: the value of the variable in the mfc dll cannot be obtained. All DLL projects used by the software must be modified. Also: ms bug: A technical document in MS shows that the "Maximize Speed" optimization option for DLL in VC5 is not fully supported, therefore, this will cause memory errors and cause program crashes.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.