(from Chapter 1 to Chapter 2, except for the Exercises)
(Example 1.5) The following code segment does not have a buffer overflow.
char buf[80];
printf(“Enter your first name:”);
scanf(“%79s”, buf);
(Program 1.1) print address of pointers using %p:
int x;
printf(“&x : %pn”, (void *) &x);
Static variables can make a program unsafe for threaded execution. In other words, they are not thread-safe.
External static variables also make code more difficult to debug because successive invocations of a function that references a static variable may behave in unexpected ways.
For these reasons, avoid using static variables except under controlled circumstances.
A common mapping divides the program image into equal-sized pieces, called pages.
Standard approaches to handling errors in UNIX programs include the following.
- Print out an error message and exit the program (only in main).
- Return -1 or NULL, and set an error indicator such as errno.
- Return an error code.
Guidelines for implementing functions: (partial)
- Do not exit from functions.
- Do not use static variables or dynamic memory allocation if automatic allocation will do just as well.
- Analyze the consequences of interruptions by signals.
- Carefully consider how the entire program terminates.
In writing general library programs, you should avoid imposing unnecessary a priori limitations on sizes.
When using malloc or a related call, analyze whether to free the memory if an error occurs or when the function returns.
(using the C library function strtok to split a string into tokens) The first call to strtok is different from subsequent calls. On the first call, pass the address of the string to parse as the first argument. On subsequent calls for parsing the same string, pass a NULL.
strtok is not thread-safe
char *strtok_r(char *restrict s, const char *restrict sep, char **restrict lasts);
Static variables are commonly used in the C implementation of a data structure as an object. The data structure and all the functions that access it are placed in a single source file, and the data structure is defined outside any function. The data structure has the static attribute, giving it internal linkage: it is private to that source file. [...] You can often make an object thread-safe by placing locking mechanisms in its access functions without affecting outside callers.
(Program 2.8) use fgets instead of gets to prevent a buffer overrun on input.
[ISO C] extern char **environ;
Be careful about calling getenv more than once without copying the first return string into a buffer. Some implementations of getenv use a static buffer for the return strings and overwrite the buffer on each call.
[ISO C] int atexit(void (*func)(void));
The C exit function calls user-defined exit handlers that were registered by atexit in the reverse order of registration. After calling the user-defined handlers, exit flushes any open streams that have unwritten buffered data and then closes all open streams. Finally, exit removes all temporary files that were created by tmpfile() and then terminates control. Using the return statement from main has the same effect as calling exit with the corresponding status. Reaching the end of main has the same effect as calling exit(0).
An abnormal termination may produce a core dump, and user-installed exit handlers are not called.