iOS defensive programming

Source: Internet
Author: User
Tags prototype definition terminates

Defensive programming is a careful, discreet way of programming. To develop reliable software, we design each component in the system so that it "protects" itself as much as possible. We have broken down the ideas that were not recorded by explicitly checking the assumptions in the code. This is an effort to prevent (or at least observe) our code from being invoked in a way that will show the wrong behavior.

Defensive programming is a programming habit that predicts where problems may arise, then creates an environment to test for errors, notifies you when a foreseen problem occurs, and performs a damage control action that you specify, such as stopping program execution, redirecting the user to a backup server, or open a debug message that you can use to diagnose the problem. These defensive programming environments are typically constructed by adding declarations to the code, performing a contract design, developing software defense firewalls, or simply adding code to validate user input.

Using defensive programming techniques, you can detect errors that may be overlooked, prevent "minor problems" that could lead to catastrophic consequences, and save you a lot of debugging time during the run-time. Defensive programming allows us to identify smaller problems as early as possible, rather than waiting for them to develop into great catastrophes. You can often see "career" developers writing code quickly and without hesitation.

The process in which they develop the software may be:

They are constantly hit by mistakes that have never had time to verify. It's hard to say that modern software engineering has progressed, but it has been happening. Defensive programming helps us write the right software from the start, without having to go through the "write-try-write-Try ..." loop process.

The software development process for defensive programming becomes:

Of course, defensive programming does not eliminate all program errors. But the problem will be less troublesome and easier to modify. Defensive programmers only catch falling snowflakes, rather than being buried in the wrong avalanche.

Defensive programming is a defensive approach, not a form of redress. We can compare it to the debug that corrects the error after the error has occurred. Debugging is how to find a remedy.

Misconceptions about defensive programming

There are some common misconceptions about defensive programming. Defensive programming is not:

Check for errors

If there is a possible error in your code, you should check for these errors in any case. This is not a defensive code. It's just a good practice to write part of the correct code.

Test

Testing your code is not a defense, but just another typical part of the development effort. Testing is not defensive, and the work can verify that the code is now correct, but there is no guarantee that the code will not go wrong after future modifications. Even with the best testing tools in the world, someone will make changes to the code and put the code into a state that has not been tested in the past.

Debugging

During debugging, you can add some defensive code, but debugging occurs after a program error. Defensive programming is the first step to "prevent" programs from making mistakes (or to find them before they appear in an incomprehensible way, or you'll need to debug all night).

Is defensive programming really worth discussing? Here are some suggestions for support and objections:

Opposing views

Defensive programming consumes the resources of programmers and computers.

-It reduces the efficiency of the Code, and even a little extra code requires some extra execution time. This may not matter for a function or a class, but if a system consists of 100,000 functions, the problem becomes serious.

-Each defensive approach requires some extra work. Why do you do all this work? You've got enough to do, don't you? Just make sure that people are using your code correctly. If they do not use the correct way, then any problem is their own cause.

Support Comments

The rebuttal is persuasive.

-Defensive programming can save a lot of debugging time, so you can do more meaningful things. Remember Murphy: Any code that could be used incorrectly will be used incorrectly.

-Write code that works correctly, just a little bit slower, much better than the code that works most of the time, but sometimes crashes (the display flashes bright color sparks).

-We can design some defensive code that is physically removed from build builds to address performance issues. In short, most of the defensive measures we consider here do not have any significant overhead.

-Defensive programming avoids a lot of security issues, which is a major problem in modern software development. Avoiding these problems can bring many benefits.

Because the market requires software development to be faster and cheaper, we need to be committed to the technology that is needed to achieve this goal. Do not skip the extra work in front of you, they can prevent future pain and project delays.

Defensive programming helps with the security of the program and can protect against such malicious abuse. Hackers and virus makers often take advantage of the rigor of code to control an application and then implement their deliberate sabotage plans. This is undoubtedly a serious threat to the modern world of software development, which concerns aspects such as productivity, money, and personal privacy.

Software abusers are diverse, ranging from irregular users who exploit small flaws in programs to professional hackers who try their best to illegally enter other people's systems. Too many programmers inadvertently leave a backdoor for these people to pass through. With the rise of networked computers, the consequences of carelessness are becoming more pronounced.

Many large software development companies are finally aware of the threat and are starting to think hard about it, devoting time and resources to rigorous defensive coding efforts. In fact, it is difficult to mend after a hostile attack.

Ii. Techniques for defensive programming

See: http://blog.csdn.net/everpenny/article/details/6316698

1, through the use of good programming style, to prevent most coding errors

Choosing a meaningful variable name, or using the parentheses carefully, can make the coding clearer and reduce the likelihood of defects appearing. It is also critical to consider a broad design before putting it into the coding process.

2, do not rush to write code

Think twice before you write every line. What kind of errors might occur? Have you considered all the logical branches that might appear? Slow down, methodical programming, though seemingly mundane, is a good way to reduce defects.

3. Don't trust anyone

Don't trust anyone. Undoubtedly, anyone (including yourself) can lead a flaw into your logic program, examining all the inputs and all the results with suspicion, until you can prove them to be correct.

Here are some of the things that may be causing you trouble:

The real user accidentally provides false input, or the wrong operation of the program, malicious users deliberately cause bad program behavior, the client code uses parameters called your function, or provide inconsistent input, the operating environment does not provide sufficient services for the program, external library run error, Do not comply with the interface protocol that you rely on;

4, the goal of coding is clear, not just concise

Simplicity is a kind of beauty, don't make your code too complicated.

5. Do not let anyone do the repair work that they should not do

Keep all variables within the smallest possible range. Do not declare global variables, as a last resort. If a variable can be declared as a local variable within a function, it is not declared on the file scope. If a variable can be declared as a local variable in the loop body, it is not declared on the function scope.

6. Check all return values

If a function returns a value, it must do so for the reason. Most of the hard-to-detect errors occur because the programmer does not check the return value. In any case, the appropriate exception is captured and handled at the appropriate level.

7. Prudent handling of memory (and other valuable resources)

8. Use of secure data structures
If you can't, then safely use a dangerous data structure.
The most common security hazard is probably caused by a buffer overflow. Buffer overflow is caused by improper use of fixed-size data structures. If your code writes this buffer before checking the size of a buffer, it is always possible that the written content will exceed the end of the buffer.
This is very easy to see, as shown in the following small section of C code:

1 char *unsafe_copy (const char *source) 2 3 {4       char *buffer = new Char[10];5 6       strcpy (buffer, source); 7 8       Retur N Buffer;9}

If the length of the data in source is longer than 10 characters, its copy will exceed the end of the memory reserved by buffer. Then anything can happen. Data errors are the best-case results-the content of some other data structures is overwritten. In the worst case scenario, a malicious user would take advantage of this simple error, add executable code to the program stack, and use it to run his own program arbitrarily, thus hijacking the computer. Such defects are often exploited by system hackers, and the consequences are extremely serious.
It's easy to avoid being attacked because of these pitfalls: Don't write such bad code! Use a more secure data structure that does not allow the program to be corrupted--using a managed buffer like the C + + string class. Or
Use secure operations for unsafe data types. By replacing the strcpy with a size-limited string copy operation strncpy, the above C code snippet can be protected.

1 char *safer_copy (const char *source) 2 3 {4       char *buffer = new Char[10];5 6       strncpy (buffer, source, ten); 7 8       R Eturn Buffer;9}

9. Initialize all variables at the declared position

10. Postpone some declaration variables as much as possible

Make the declaration position of the variable as close as possible to where it is used, thus preventing it from interfering with other parts of the code. Instead of reusing the same temporary variable in multiple places, variable reuse can complicate the work of later re-perfecting the code.

11. Prudent casting

If you really want to use coercion, you have to think it through. What you're telling the compiler is: "Forget the type check, I know what this variable is, and you don't know." "You ripped a big hole in the type system and went straight through the past. This is not reliable.

12. Other

Provide the default behavior

The habit of obeying language

Check the upper and lower limits of values

Set constants Correctly

Third, assert assertion

Transferred from: http://wenku.baidu.com/view/3daa77c689eb172ded63b787.html

Assert assertions are often used in defensive programming and are a necessary tool.

ASSERT () is a macro defined in <assert.h> that is used to test assertions. An assertion essentially writes down the programmer's assumptions, which, if assumed to be violated, indicates a serious program error. For example, a function that assumes that only a non-null pointer is accepted can write:
ASSERT (P! = NULL);
A failed assertion interrupts the program. Assertions should not be used to catch unexpected errors, such as the failure of malloc () or fopen ().

Not used to check for errors.

When a programmer has just started using assertions, it is sometimes wrong to use assertions to check for real errors without checking for illegal situations. Take a look at the two assertions in the following function StrDup:

1  char* strdup (char* str) 2  {3        char* strnew; 4        assert (str = NULL);    error! 5  6        strnew = (char*) malloc (strlen (str) +1); 7        assert (strnew! = NULL); 8  9        strcpy (strnew, str); 10        return (strnew);  

The first assertion is used correctly, because it is designed to check for illegal situations that should never occur when the program is working properly. The second assertion is quite different in its use, and it tests the error condition, which is an error condition that is sure to occur in its final product and must be processed.

The program is generally divided into debug version and release version, debug version for internal debugging, release version released to the user.
Assert assert is a macro that works only in the debug version, and it is used to check what should not happen. The following is a memory copy program that, during the run, if the assert parameter is False, then the program aborts (there will generally be a prompt dialog stating where the Assert was raised).

1//Copy non-overlapping memory block  2 void memcpy (void *pvto, void *pvfrom, size_t size)  3 {  4       void *pbto = (byte *) pvto;  5       void *pbfrom = (byte *) Pvfrom;  6  7       assert (pvto! = NULL && Pvfrom! = null);  8  9       while (Size--> 0)       *pbto + + = *pbfrom + +; 11 12       

Assert is not a hastily pieced up macro, and assert should not produce any side effects in order not to cause differences in the debug and release versions of the program. So assert is not a function, but a macro. Programmers can think of assert as a harmless test that can be safely used in any system state.


Here are a few principles for using assertions:
1) Use assertions to catch illegal situations that should not occur. Do not confuse the difference between the illegal situation and the wrong situation, the latter being inevitable and must be dealt with.
2) Use assertions to confirm the parameters of the function.
3) When writing a function, repeat the examination, and ask yourself: "What assumptions do I intend to make?" Once the assumptions have been determined, the assumptions are checked using assertions.
4) General textbooks encourage programmers to design for error-proof, but keep in mind that this style of programming conceals errors. When error-proof programming occurs, an assertion is used to alert you if the "impossible" thing does happen.

C + + assert () assertion mechanism (reprint)

ASSERT () only works if the debug code is generated.
The compiler skips assert () when generating the release code.

ASSERT () is used to check if the result of the operation above is correct, such as the return of the pointer is not correct, the expression is not "false", the error is to write information and exit the program.

ASSERT () is a macro that is used frequently when a debugger is run, and it calculates the expression in parentheses when it runs, and if the expression is False (0), the program reports an error and terminates execution. If the expression is not 0, the following statement continues. This macro usually turns out that there is clearly illegal data in the program, and if a termination procedure is used to avoid serious consequences, it is also easy to find errors.

1//Prototype definition: 2 #include <assert.h> 3 void assert (int expression_r_r_r); The function of 4/*assert is to calculate the expression Expression_r_r_r, if its value is false (that is, 0), then it first prints an error message to stderr, and then terminates the program by calling abort. Take a look at the following list of programs Badptr.c:5 */6  7 #include <stdio.h> 8 #include <assert.h> 9 #include <stdlib.h>10 int mai n (void) One {       *fp;13       fp = fopen ("Test.txt", "w");//Open a file in a writable manner and create a file with the same name if it does not exist       (FP);     OK15       fclose (FP);       fp = fopen ("Noexitfile.txt", "R");//Open a file in a read-only manner and open failure if it does not exist       (FP);//err or!19       fclose (FP);//!!!! The program will never execute here.       return 0;21}22/*[[email protected] error_process]# gcc badptr.c23 *[[email protected  ] Error_ process]#./a.out24  *a.out:badptr.c:14:main:assertion ' fp ' failed.25  * Waived  

The disadvantage of using assert is that frequent calls can greatly affect the performance of the program and add additional overhead.
After debugging, you can disable the Assert call by inserting the #define NDEBUG before the statement that contains # include <assert.h>, as shown in the following example code:

#include <stdio.h>
#define Ndebug
#include <assert.h> Usage Summary and precautions:


1) Verify the legitimacy of incoming parameters at the beginning of the function
Such as:

int resetbuffersize (int nnewsize) {/* Function: Change buffer size, * parameter: nnewsize buffer new length * Return value: Buffer Current length * Description: Keep original information content unchanged nnewsize<=0 indicates clear buffer * /     assert (nnewsize >= 0);     ASSERT (Nnewsize <= max_buffer_size);     ...}

2) Each assert examines only one condition, because when multiple conditions are checked, if the assertion fails, it is not possible to visually determine which condition failed
Bad: Assert (noffset>=0 && noffset+nsize<=m_ninfomationsize);
Good: Assert (noffset >= 0);
ASSERT (Noffset+nsize <= m_ninfomationsize);

3) You cannot use a statement that alters the environment, because assert only takes effect in debug, and if you do, you will use the program to run into problems when it is actually running
Error: Assert (i++ < 100)
This is because if there is an error, such as i=100 before execution, then this statement will not be executed, then i++ This command will not be executed.
Correct: Assert (I < 100)
i++;


4) Assert and subsequent statements should be empty lines to create a logical and visual sense of consistency


5) In some places, assert cannot replace conditional filtering
Assert is only valid in debug versions and is ignored if compiled to release version. (in C, assert is a macro instead of a function), using Assert "assert" is easy to output a program error at debug time.
The function of assert () is similar, it is a function specified in the ANSI C standard, and an important difference between it and assert is that it can be used in release version.

Assert assert VERIFY

Assert name Set condition Release Debug whether there is a reporting impact factor
Assert does not perform a ndebug/_debug definition by default
ASSERT default does not perform a
VERIFY default execution of the release environment is not available, the debug environment has
Summarize:
Assert: In relation to the definition of Ndebug/_debug, Ndebug macros do not work when they exist.
ASSERT: Function in debug environment, and report, release environment does not work.
VERIFY: In Debug and release all work, different place is, in the debug environment, there are reports, release under no report.

iOS defensive programming

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.