Static code check tool PC-LINT (1)

xiaoxiao2021-04-07  361

Author: Xinggui (oRbIt) E_Mail: inte2000@163.com

[Part of this article "from the PC-Lint user manual, when translated, add some understanding]

Summary: The syntax of the C / C language has the flexibility of other languages. This flexibility brings the improvement of code efficiency, but the possibility of increasing hidden dangers in the code. The static code check tool PC-LINT is biased on the logic analysis of the code, which can discover potential errors in the code, such as an array access, memory leak, and uninited variables. This article will show how to install and configure the PC-Lint code check tool and how to integrate PC-LINT with common code editing software.

Keywords: code check PC-LINT rule option

Directory Summary 1 Introduction 2 PC-LINT Introduction 3 PC-LINT Code Check Function 3.1 Strong Type Check 3.2 Variable Variable Variable Variable Variables 3.4 Weak Definition Check 3.5 Format Check 3.6 Readitation Check 3.7 Const Variables Check 3.8 Volatile Variables Check 4 PC-LINT Software Usage 4.1 Installation and Configuration 4.2 Integration of PC-LINT and Common Development Tools (Visual C , Source Insight, Uedit) 5 Summary Reference Appendix A PC-LINT Important Document Description Appendix II Error Information Forbidden Option Description Common mistakes in Appendix III PC-LINT Test

I. Introduction

The syntax of the C / C language has no flexibility in other languages. This flexibility brings the improvement of code efficiency, but corresponding to the code writing has a lot of arbitrarily, and the C / C compiler does not make mandatory types. Check, do not do any boundary check, which increases the possibility of hidden dangers in your code. If these potential errors can greatly reduce the pressure of the testers before the code submission test, reduce the inclination cost of the software project, but the traditional C / C compiler has no power, this task can only be dedicated The code check tool is done. There are currently a lot of C / C static code check tools, where Logiscope Rulechecker and PC-Lint are currently applying a relatively wide application. These two inspection tools have features, and logiscope ruleChecker tends to check the code coding specification, such as code indent format, CASE statement writing specification, function declaration, and Boolean expression rules, and PC-LINT is called by code. Logic analysis, it can discover potential errors in the code, such as array access, memory leaks, and uninitialized variables. This article describes how to install and configure the PC-Lint code check tool and how to edit software, such as Visual C , Source Insight, which will also briefly introduce some PC-LINT common code check options.

Two PC-LINT Introduction

PC-LINT is a C / C software code static analysis tool developed by Gimpel Software. It is a full name of PC-Lint / Flexelint for C / C , and PC-Lint can be used on Windows, MS-DOS, and OS / 2 platforms. Published in the form of binary executables, while Flexelint is running in other platforms, published in the form of source code. PC-Lint has a wide range of customer bases around the world, and many large software development organizations check PC-Lint as the first step in the code takes place. PC-LINT can not only perform global analysis of the program, not identifying an array subscript that has not been properly verified, the report is not initialized, but the warnings use the empty pointer and redundant code, but also can effectively help you make many programs in space utilization , Improvement points on operational efficiency. Through the following example, you can see the powerful function of the PC-LINT tool: 1: 2: CHAR * REPORT (int M, int N, char * p) 3: {4: int result; 5: char * TEMP; 6: Long nm; 7: I, k, kk; 8: char name [11] = "joe jakeson"; 9: 10: nm = n * m; 11: TEMP = P == "" "NULL": P 12: for (i = 0; i 0) Result = 1; 20: ELSE IF (KK <0) Result = -1; 21: 22: IF (m == Result) Return (TEMP); 23: Else Return (Name); 24:}

This is a C code that can be checked by most common C language compilers, but PC-Lint can find errors and potential issues: 8th lines throw away NUL characters when they assign values ​​to the Name array, 10th The multiplication accuracy of the line will be misaligned. Even if the length of the Long is longer than INT, due to the symbol bit, it will cause accuracy to be misalignment, and the 11th line is problematic, and the variable K of the 14th line is not initialized. 15 lines of KK may not be initialized, and the results of the 22nd line may not be initialized, and the line 23 returns to the address of a partial object. With the appearance of C language, the C / C compiler has a stricter syntax check, but still cannot avoid a bug program. The type of C is still not as strict as Pascal. For a small program, most of the programmers can find out the error above, but find out these flaws from a large software with thousands of lines of lines, and no one can guarantee This type of question is available. If you use PC-LINT, you can check these errors with a simple compilation, which will save a lot of development time. in some sense. PC-LINT is a more stringent compiler that can be checked out in addition to a general grammatical error, but it is probably a potential, not easy to discover. Three PC-LINT code check function

PC-LINT can check a lot of grammatical errors and syntax correct logic errors, PC-LINT is assigned an error number for most of the error messages, and the number of error numbers that are less than 1000 is assigned to the C language, the number greater than 1000 errors The number is used to illustrate the C error message. Table 1 lists detailed categories of PC-Lint alarm messages:

Table 1 lists PC-LINT alarm message classification

Error Description CC alarm level syntax error 1-1991001-11991 internal error 200-299 0 fatal error 300-399 0 alarm 400-6991400-16993 optional information 900-9991900-19994 Taking C language as an example, The number 1-199 refers to the syntax error that the general compiler also produces; the number 200-299 is an error inside the PC-Lint program. This type of error will not appear in the code; No. 300-399 refers to System fatal errors caused by memory restrictions. The prompt information that appears in Number 400-999 is classified according to the possibility of hiding code issues: Number 400-699 refers to alarm information that is likely to have problems in the checked code; appearing in number 700-899 Information, the possibility of generating errors is lower than the alarm information, but may still be due to the problem caused by code problems. Number 900-999 is an optional information that will not be checked by default unless you specify them in the options. PC-LINT / FELEXLINT provides a alarm level setting option -Wlevel, similar to many compilers, and its alarm level is divided into the following levels, the default alarm level is level 3: -w0 does not generate information (except for fatal Error) -w1 only generate error messages - no alarm information and other prompt information -w2 only error and alarm information -w3 generation errors, alarms, and other prompt information (this is the default setting) - W4 Generate all information PC-LINT / FELEXLINT It also provides alarm level setting option -wlib (level) for handling the header file of the Library, this option does not affect the alarm level of the processing C / C source code module. It has the same alarm level with -Wlevel, the default alarm level is level 3: -wlib (0) Does not generate any library information - WLIB (1) only generate error messages (when the source code of the library) -wlib (2 Generate errors and alarm information -wlib (3) generate errors, alarms, and other information (this is the default setting) -wlib (4) Generates all information PC-LINT checks a lot of types, strong type check, variable value tracking, Semantic information, assignment order check, weak definition check, format check, indentation check, Const variable check, Volatile variable check, etc. For each check type, PC-LINT has a lot of detailed options to control the check effects of PC-LINT. PC-LINT options have more than 300, these options can be placed in the comment (inserted into the code in the form of an comment), for example: / * Lint Option1 option2 ... Optional Commentary * / option can have multiple rows // lint option1 Option2 ... Optional Commentary option is only separated by space (for C ) options, and the lint command must be lowercase and keep it behind / * or //, and there is no space. If the option consists of a part similar to the operator and an operand, for example, -esym (534, Printf, Scanf, Operator New), where the last option is Operator New, then there can be only one space in the middle of Operator and New. The PC-LINT option can also be placed in the macro definition, and when the macro is exposed, the option takes effect.

For example: #define divzero (x) / * lint -save -e54 * / ((x) / 0) / * Lint -Restore * / Allows 0 without the alarms will introduce the common use of PC-LINT, but also comparison Important code check types, and examples show the alarm information that may occur under each check type and usage of common options: 3.1 Strong Type Check Strong Type Check Options "-strong" and its auxiliary (supplement) option "-index" Strong type checks for TypedEf defined data types to ensure that variables between only the same type can assign each other, strong Type Check Options Strong usage is: -strong (Flags [, name] ...) Strong option must be in Typedef Open before defining the type, otherwise the PC-LINT cannot identify the data type defined by typedef, and the type check will be invalid. The Flags parameters can be A, J, X, B, B, L and F, the corresponding interpretation and weakening characters listed in Table 2: Table 2 Type Check Strong Options and Parameter Table

A Type check when you assign strong type variables, including: direct assignment, return value, parameter transfer, initialization. A parameter can be followed by the following characters, used to weaken A check intensity: i ignore the initialization R ignore the RETURN statement P ignore the parameter transmission A ignore the assignment operation C ignore the assignment of constant (including integer constants, constant strings, etc.) to strong types The case z ignores ZERO assignment, ZERO is defined as any unforgettable converted into strong 0 constants. For example: 0L and (int) 0 are Zero, but (handle) is not Zero when Handle is a strong type. (Handle *) 0 nor, for example, using-Strong (AI, BITS) settings, PC-Lint will issue a alarm to code from non-BITS type data to BITS type data, but ignore this type of assignment when the variable is initialized. X Type Check when strong type variables are made to other variables. Weaken parameters I, R, P, A, C, and Z are also suitable for X and serve as the same effect. The j option is checked when the strong type is subjected to the following binary operation, the following is the parameter of J: E ignore ==,! = And?: Operator R ignore>,> =,

Below with a code Demo-Strong option: // lint -strong (ab, bool)

Below is an example of using Index: // lint -strong (azjx, count, temperature) // lint -index (d, count, temperature) // only count can index a TemperatureTyPedef float temperature; typedef int count; temperature; tem 100]; // ok Because Of D flagtemperature * pt = t; // Pointers Are Also Checked // ... within a functioncount i; t [0] = t [1]; // Warnings, NO C Flagfor (i = 0; i <100; i ) T [I] = 0.0; // ok, I is a count119pt [1] = 2.0; // Warningi = Pt - t; // ok, PT-T is a count above In the example, Temperature is a strong index type, and Count is a strong index type. If D option is not used, the length of the array will be mapped into an inherent type: Temperature T [(count) 100]; however, this is a small trouble, which defines the array length into constant as appropriate: #define max_t ( COUNT) 100Temperature T [MAX_T]; this is also a benefit that the same MAX_T can also be used in the For statement to limit the scope of the for statement. It should be noted that pointers that point to strong index types (eg, PT above) If used in [] symbols (array symbols), it will be checked. In fact, whenever, as long as a value is added to a pointer pointing to the index type, this value is checked to confirm that it is a strong index type. In addition, strongly reached a value if a value is subtracted, the result is considered to be a normal strong index, so the following example does not generate alarm: i = pt - t; 3.2 Variable value tracking 3.2.1 Variable value initialization tracking early Variable value tracking technology is mainly tracking the initialization of variable values, and the LINT messages associated with variable initialization are mainly 6444, 645 ("variable may not have initialization"), 771, 772 ("unreliable initialization"), 530 ( "Not initialized"), And 1401 - 1403 ("Member ... Not initialized"). The following code is an example: if (a) b = 6; ELSE C = B; // 530 Messagea = C; // 645 Message assumes that B and C are not initialized before, PC-LINT will report B not initialization (When it is assigned to C, C may not be initialized (when giving a assignment). While and for cycle statements and the IF statements above are slightly different, compare the following code: while (n--) {b = 6; ...} c = b; // 772 Message hypothesis B is not used It is initialized, which reports B may not be initialized (when the C is assigned to C). The reason for this is because the programming can know that such a cycle is always at least once. On the contrary, the previous IF statement is more difficult to determine if the IF statement will always be executed, because if this is the case, such an IF statement is excessive and should be removed.

The While statement is similar to if, look at the example below: Switch (k) {case 1: b = 2; break; case 2: b = 3; / * Fall Through * / case 3: a = 4; Break; Default: Error ();} c = b; // 645 Message Although b is assigned in two different places, there is still possible possibilities that B is not initialized. Therefore, when b assigns to C, a message that may not be initialized will occur. In order to solve this problem, you can assign a default value to B before the Switch statement. Such PC-LINT will not generate alarm messages, but we have lost opportunities to initialize the variable initialization caused by the PC-LINT to check the number of variables caused by subsequent code modifications. A better way is to modify the CASE statement that is not assigned to b. If the error () statement takes place to "impossible happens", then we can let PC-Lint know this is actually impossible, the following code indicates this: Switch (k) {casse 1: B = 2; Break; Case 2: Case 3: B = 3; a = 4; Break; default: error (); / * lint -unreachable * /} c = b; Note: Here: Here, the -unreachable should be placed in Error (), Behind, front of Break. Another way to generate a "no initialization" alarm is to pass a pointer to free (or a similar method). For example: if (n) free (p); ... p-> value = 3; the message that p may not be initialized when accessing P. For goto statements, the forward GOTO may generate uninitialization messages, and backward GOTO will be ignored to this check. IF (a) goto label; b = 0; label: c = b; when using uninitialized variable check in a large project, some errors may be generated. The generation of this report, a large part from a bad program style, or includes the following structure: if (x) Initialize Y ... if (x) Use Y, when this happens, you can use it. In the way, the initial value is assigned, or the option -esym (644, y) is used to turn off the initialization check above the variable Y. 3.2.2 Variable Value Tracking Variable Value Tracking Technology Collect information from assigning statements, initialization, and conditional statements, and the parameters of the function are default that in the correct range, only the information that can be collected from the function and this does not match this The alarm will be produced. Related messages related to variable values ​​are: (1) Access address crossed message (Message 415, 661, 796) (2) Error used by 0 division (54, 414, 795) (3) NULL pointer (413, 613 , 794) (4) Creating errors (416, 662, 797) (5) Redundant Boolean test (774) Looks below: int A [10]; int F () {INT K; K = 10; RETURN A [K]; // Warning 415} This statement generates a warning 415 (through the '[' access the crossed pointer), because PC-Lint saves the value assigned to K, then perform when using K Judgment.

If we call the above example: int A [10]; int F (int N) {INT K; if (n) k = 10; ELSE K = 0; Return a [k]; // Warning 661} This will generate alarm 661 (possibly accessing the basement pointer). Use "possible" because it is not all paths to assign 10 to k. PC-LINT not only collects assignment statements and initialization, but also information from the condition statement. For example, the following example: int A [10]; INT F (int K, int N) {IF (k> = 10) a [0] = n; Return a [k]; // Warning 661 - K Could Be 10} There is still a 661 alarm, because PC-LINT detects that when using K, the value of K> = 10. In addition, for functions, it always assume that K is correct, the program user knows what they want, so the following statement does not generate alarm: int A [10]; int F (int K, int N) {RETURN A [K N];} // no warning and check variables are not initialized, and if the value of the variable is correct. For example, if the loop in the following example is not running once, K may be out of the range. At this time, a message 796 will generate .int A [10]; int F (int N, int K) {INT m = 2; if (k> = 10) m ; // HMM - SO K Could BE 10, EH? While (N -) {m ; k = 0;} Return A [K]; // Info 796 - - K Could Still BE 10} The following example demonstrates that the NULL pointer Question: INT * f (int * p) {if (p) printf ("/ n"); // so - pink be nullprintf ("% d", * p); // WarningReturn P 2; / / Warning} There will be two alarms here, because the NULL pointer may be used, which is obvious that both statements should be within the range of the IF statement. In order to make your program more robust, you may need to open the switch ( FPN) of Pointer-Parameter-May-Be-Null. This option assumes that all poks that are passed to functions may be NULL. The array boundary value is detected in the high position, that is, INT A [10]; ... a [10] = 0; detected, and A [-1] is not detected. Two messages in PC-Lint are related to the critical inspection of the pointer, one is the creation of the offshore pointer, and the other is the access to the crossed pointer, that is, the value of the crimp is obtained.

In ANSI C ([1] 3.3.6), it is allowed to create a pointer to the end of the end of the array, such as int a [10]; f (A 10); // OKF (A 11); // Error But the two pointers created above are unable to access, such as int A [10], * p, * q; p = a 10; // ok * p = 0; // Warning (Access Error) p [-1] = 0; // no warningq = p 1; // Warning (CREATION Error) q [0] = 0; // Warning (Access Error) Boolean condition Check is not as strict, but it A alarm will be generated on the Boolean condition of Hengzhen, such as if (n> 0) n = 0; ELSE IF (n <= 0) n = -1; // Info 774 The code above the alarm (774), because The second condition check is constant, it can be ignored. This redundant code does not cause problems, but it is often used for logical errors or an error that can occur in detail. 3.2.3 Recovery in some cases using Assert, although we can know the exact value based on the code, but PC-LINT cannot obtain the range of the value of the variable in all cases, this time will generate some error alarms Information, we can use the ASSERT statement to increase variable range information, to suppress the generation of the alarm information of these errors. The following example shows: char buf [4]; char * p; strcpy (buf, "a"); p = buf strlen (buf); // p is 'possibly' (buf 3) P ; //p IS 'POSSIBLY' (BUF 4) * P = 'a'; // Warning 661 - Possible Out-of-Bounds ReferencePC-LINT cannot know how much the value of variables in all cases. In the above example, the statement that produces alarm does not actually bring any hazard. We can use * p = 'a'; // Lint! E661 to suppress the alarm. In addition, we can also use the Assert tool to correct this problem: #include ... char buf [4]; char * p; strcpy (buf, "a"); P = BUF Strlen (buf) (P

For example, suppose Assert is implemented by the following compiler macro: #define assert (p) ((void) 0: __a (...)) Considering __a () pops up a message and not Will return, so this need to be added is: -Function (exit, __a) This option passes some of the non-return feature of the EXIT function to the __a function. As a result, the compiler may implement Assert into a function, for example: #define assert (k) _assert (k, ...) In order to let PC-Lint know _assert is an Assert function, you need to use -function __ASSERT, _ASSERT "option or -function (__ASSERT (1), _assert (1)) Option Copy __ASSERT () Semantic Semantic Many Compile Options in the Compile Options file already exists, if not, you can copy one Assert.h file to the PC-Lint directory (this directory is used in order of the sequence of file searches for the compiler). 3.2.4 Function Internal Variable Tracking PC-LINT Function Value Tracking Features Tracking those that will be passed to functions (as function parameters) variable, which are used to initialize function parameters when the function is called. This tracking function is used to measure return values, record additional function calls, of course, can also be used to detect errors. Example code: T1.cpp: 1 int F (int); 2 int G () 3 {RETURN F (0);} 4 INT F (int N) 5 {Return 10 / n;} In this example When F () is called, use 0 as a parameter, which will cause the 10 / n statement that has not been problematic, generated by the 0 division, using the command Lin -u t1.cpp to get the following output: --- Module: T1. Cppduring specific Walk: File t1.cpp line 3: f (0) T1.cpp 5 Warning 414: Possible Division By 0 [Reference: file t1.cpp: line 3] You first noticed something is phrase "During Specific Walk ", followed by the location, function name, and parameters that occurred in the function call, and then the error message. If an error message is missing in the error message and the indication information used to mark an error location is because the code (the code that is called function) has passed when checking the error. If you switch the position of the two functions like the same below: t2.cpp: 1 int F (int N) 2 {return 10 / n;} 3 int g () 4 {returnif (0);} In this case The alarm of 0 except, because f (0) at the fourth line, the code of function f () has passed, in which case the multi-pass option is required. If you use Lin -u -Passes (2) t2.cpp command in just now, the output becomes: --- Module: t2.cpp /// Start of Pass 2 /// --- Module: T2 .cppduring specific Walk: File t2.cpp line 4: f (0) T2.cpp 2 Warning 414: Possible Division By 0 [Reference: File T2.cpp: line 4] Use the -passes (2) option will check the code two All over, some operating systems do not support using -Passes (2) in the command line, for such systems, can be replaced with -Passes = 2 or -Passes [2].

It can be seen by lengthy information, and the first check is not generated in PASS 2. This time, the error message is different from the previous time. In some cases we can infer the return value of the specified function call, at least some of the return values. The following module is: t3.cpp: 1 int F (int N) 2 {RETURN N - 1;} 3 int N) {RETURN N / F (1);} Using the command Lin -u - Passes (2) T3.cpp, you can get the following output information: --- Module: t3.cpp /// Start of Pass 2 /// --- Module: T3.cpp {Return n / f (1);} T3.CPP 4 Warning 414: Possible Division By 0 [Reference: File T3.cpp: Lines 2, 4] First-pass check We know that the call function f () passed is 1, the second pass checks the function f (), We infer this parameter will result in the return result is 0, when the second pass is checked to start processing function G (), generated by an error is generated. It should be noted that this information is not previously appeared before the phrase "during specific Walk", because the error detected during the normal processing of the function g (), and is not used as function G () at this time. The value specified by the parameter. The specified function call can generate additional function calls, if we pass enough detection times, this process may repeat, refer to the following code: T4.cpp: 1 int F (int); 2 int N) 3 {RETURN F (2); 4 INT F (int N) 5 {RETURN N / F (N - 1);} The fifth line of denominator F (N-1) does not cause suspicion, until we realize F (2) Call will cause f (1) call, eventually call f (0), forcing the final return value of 0. Use the following command line: Lin -u -Passes (3) T4.cpp, the output is as follows: --- Module: t4.cpp {returnif (2);} T4.cpp 3 info 715: Symbol 'n' ( LINE 2) Not Reference /// Start of Pass 2 /// --- Module: T4.cpp /// Start of Pass 3 /// --- Module: T4.cppduring Specific Walk: File T4.cpp Line 3 : f (2) file t4.cpp line 5: f (1) T4.cpp 5 Warning 414: Possible Division By 0 [Reference: File T4.cpp: Lines 3, 5] has been dealt with three times Possible 0 removal of errors, you want to know why you need to handle three times to look at this option -specific_wlimit (n). It should be noted that the specified call sequence, f (2), f (2) are present as a preamble as alarm information. 3.3 Assignment Sequence Check When an expression value depends on the order of assignment, alarm 564 will be generated. This is a very common problem in the C / C language, but few compilers will analyze this situation.

转载请注明原文地址:https://www.9cbs.com/read-132586.html

New Post(0)