C basic memory out-of-bounds and memory monitoring for simple processing, out-of-bounds monitoring
Introduction
Suddenly I felt like I was about to go out for a walk. After I woke up, I brushed my teeth and contacted coding. I knew it was dusk.
Look at the sky, turn on the light, and feel the night and night.
When I worked in Beijing for 13 years, I met a batch of NB colleagues of the same age. I work together, I like to exercise, and I study quietly.
Discover a fact from others.
If we are just as smart,
When you complain about your hard work, it is still so watery; in fact, they are desperately trying, and you are just trying,
If we are not smart,
If it cannot be enabled, what will happen? x.
Preface-Out-Of-Memory Processing
Let's first look at the design diagram. The principle of out-of-bounds memory check is as follows:
The above principle is not very simple, and this is exactly the most common practice. Beauty is not responsible. Beauty is very important.
Follow the above design ideas to build the interface file first.Checkmem. h
# Ifndef _ H_MEMCHECK_CHECKMEM # define _ H_MEMCHECK_CHECKMEM # include <stddef. h>/** encapsulate malloc and add the Boundary Detection memory block * (inline originally divided into _ DEBUG with macro processing, followed by no equals to useless) * sz: Applied Memory Length *: the first address of the returned memory */extern inline void * mc_malloc (size_t sz);/** encapsulate calloc and add the Boundary Detection memory block * cut: Number of Applications * sz: each size */extern inline void * mc_calloc (size_t cut, size_t sz);/** encapsulates relloc, also added memory blocks for Edge Detection */extern inline void * mc_realloc (void * ptr, size_t sz) ;/** Check the memory to see if there is an error. If there is an error, print the error message. * check only the memory size obtained by check _ */extern inline void mc_check (void * ptr ); # endif //! _ H_MEMCHECK_CHECKMEM
It is mainly used to add memory blocks at the end and header of malloc, calloc, and realloc. This is a simple step. If you can understand the above design concept diagram.
These codes can be skipped. The idea is more important than the code. Well, we will continue to show the implementation part.Checkmem. c
# Include "checkmem. h "# include <stdio. h> # include <errno. h> # include <string. h> # include <stdlib. h> // the error message is printed on the console. fmt must be a macro enclosed in double quotation marks # define CERR (fmt ,...) \ fprintf (stderr, "[% s: % d] [error % d: % s]" fmt "\ r \ n", \ _ FILE __, _ func __, _ LINE __, errno, strerror (errno), ##__ VA_ARGS _) // print the error message on the console and exit, t. Similarly, fmt must be a String constant enclosed by "" # define CERR_EXIT (fmt ,...) \ CERR (fmt, ##__ VA_ARGS _), exit (EXIT_FAILURE) // Number of inserted bytes # define _ INT _ CHECK (1 <4)/** encapsulate malloc and add the Boundary Detection memory block * sz: Applied Memory Length *: the first address of the returned memory */inline void * mc_malloc (size_t sz) {// memory detection blocks are added to the header and tail. The default value is 0x00 char * ptr = calloc (1, sz + 2 * _ INT_CHECK); if (NULL = ptr) {CERR_EXIT ("malloc sz + sizeof struct check is error! ");} // Save the last memory block address size in the first four bytes size_t * iptr = (size_t *) ptr; * iptr = sz + _ INT_CHECK; return ptr + _ INT_CHECK;}/** encapsulate calloc and add the Boundary Detection memory block * cut: Number of Applications * sz: each size */inline void * mc_calloc (size_t cut, size_t sz) {return mc_malloc (cut * sz);}/** encapsulates relloc, also added memory blocks for Edge Detection */inline void * mc_realloc (void * ptr, size_t sz) {// check the memory mc_check (ptr) first ); // re-apply for the memory char * cptr = (char *) ptr-_ INT_CHECK; char * nptr = Calloc (1, sz + 2 * _ INT_CHECK); if (NULL = nptr) {CERR_EXIT ("realloc is error: % p. ", ptr);} // memory movement size_t * bsz = (size_t *) cptr; memcpy (nptr, cptr, * bsz <sz? * Bsz: sz); * bsz = sz; free (cptr); return nptr;} // check whether the memory is incorrect. if the error is returned, true is returned, print Information static void _ iserror (char * s, char * e) {while (s <e) {if (* s) {CERR_EXIT ("Need to debug test !!! Ptr is: (% p, % p). check is % d! ", S, e, * s) ;}+ + s ;}/ ** checks the memory to see if an error occurs. If an error occurs, print the error message directly. * You can only detect the error, check _ * Memory */inline void mc_check (void * ptr) {char * sptr = (char *) ptr-_ INT_CHECK; // first check the header char * s = sptr + sizeof (size_t); char * e = sptr + _ INT_CHECK; _ iserror (s, e ); // check the tail size_t sz = * (size_t *) sptr; s = sptr + sz; e = s + _ INT_CHECK; _ iserror (s, e );}
Code implementation is quite regular and easy to implement. It is just a hundred lines. You can view the implementation according to the interface files one by one. It is easy to learn the skills in development and improve practical skills.
Even though C and C ++ have a high level of skills, they do not like to write comments. This strongly recommends that not a great guy write more comments.
Don't talk about anything <code is a comment>. Writing more comments is easy to deepen your second thinking and speed up your growth. Don't learn this from old developers. If you change jobs, you will encounter a big project.
Comments are equivalent. How do you feel? Leave more paths for us and write more comments.
Check the test code.Main. c
# Include <stdio. h> # include <stdlib. h> # include "checkmem. h "/** demonstrate a way to detect memory out of bounds * Add upper and lower limits */int main (int argc, char * argv []) {// The experiment step is, yes applied memory, in the Operation memory char * as = mc_malloc (16); mc_check (as); // memory out of bounds // as [16] = 18; // mc_check (as); // re-allocate the memory and cross-border again as = mc_realloc (as, 15); as [15] = 44; mc_check (); free (as); return 0 ;}
Test Results
The idea and implementation of memory out-of-bounds have been completed. Please try again.
Body-memory global monitoring
The idea of memory global detection is simpler. The reference 'counting method' is used for processing. A lot of automatic garbage collection machines use the reference counting method.
Including kernel layer, such as file descriptor, IPC shared memory, and message mechanism.Memglobal. h
# Ifndef _ H_MEMGLOBAL_MEMGLOBAL # define _ H_MEMGLOBAL_MEMGLOBAL # include <stddef. h> # include <stdlib. h>/** simple monitoring of global startup memory */extern inline void mg_start (void);/** added malloc for global counting * sz: memory size to be allocated *: return the first address of the allocated memory */extern void * mg_malloc (size_t sz);/** Add the global count calloc * SC: Number of allocated * sz: size of each allocation *: returns the first address of the allocated memory */extern inline void * mg_calloc (size_t SC, size_t sz);/** added realloc * ptr: last allocated memory address * sz: waiting Re-allocated memory size *: returns the re-allocated memory address */extern void * mg_realloc (void * ptr, size_t sz ); /** added memory free for counting Processing * ptr: pointer of the address returned by the above function */extern inline void mg_free (void * ptr ); // enable global memory usage count in test mode # if defined (_ DEBUG) # define malloc runtime # define calloc mg_calloc # define realloc mg_realloc # define free mg_free # else # define malloc # define calloc # define realloc # define free # endif // ! _ H_MEMGLOBAL_MEMGLOBAL
It's still beautiful.Memglobal. c
# Include "memglobal. h "# include <stdio. h> # include <errno. h> # include <string. h> # include <stdlib. h> // cancel the built-in macro to prevent recursion # undef malloc # undef calloc # undef realloc # undef free // print the error message on the console, fmt must be a macro enclosed in double quotes # define IOERR (io, fmt ,...) \ fprintf (io, "[% s: % d] [error % d: % s]" fmt "\ r \ n", \ _ FILE __, _ func __, _ LINE __, errno, strerror (errno), ##__ VA_ARGS _) // global memory count, when the system is constructed for the first time, it is 0 static int _ mct; # define _ STR_MGTXT "check Mem. log "// when the mg memory is monitored and exited, some information is recorded static void _ mg_exit (void) {if (_ mct = 0) return; // print the information to IOERR (stderr, "Detect memory leaks _ mct = % d !! ", _ Mct); // output to FILE * txt = fopen (_ STR_MGTXT," a "); if (txt = NULL) {IOERR (stderr, "fopen" _ STR_MGTXT "a is error! "); Return;} IOERR (txt," Detect memory leaks _ mct = % d !! ", _ Mct); fclose (txt);}/** simple monitoring of global startup memory */inline void mg_start (void) {// register the exit monitoring event atexit (_ mg_exit);}/** increase the global count of malloc * sz: memory size to be allocated *: returns the allocated memory first address */void * mg_malloc (size_t sz) {void * ptr = malloc (sz); if (! Ptr) return NULL; ++ _ mct; memset (ptr, 0x00, sz); return ptr;}/** added the calloc * SC for global counting: number of allocations * sz: size of each allocation *: return the first address of the allocated memory */inline void * mg_calloc (size_t SC, size_t sz) {return mg_malloc (SC * sz );} /** added realloc * ptr: memory address allocated last time * sz: memory size to be re-allocated *: returns the allocated memory address */void * mg_realloc (void * ptr, size_t sz) {if (! Ptr) return mg_malloc (sz); return realloc (ptr, sz);}/** added memory free * ptr for counting: the above function returns the address pointer */inline voidmg_free (void * ptr) {if (! Ptr) return; -- _ mct; free (ptr );}
Intermediate
// Cancel built-in macros to prevent recursion # undef malloc # undef calloc # undef realloc # undef free
This is mainly used to solve the problem that the reference of the header file memglobal. h will cause recursive calling. There is another idea on Linux that does not include this header file.
The gcc can be specified at the link, but vs is automatically deduced and compiled. If it is not introduced, it cannot be deduced. The above general practice is adopted later.
The above idea is to first start the global memory monitoring function, and then use a special macro to replace the original application and release functions.
Test FileMain. c
# Include <stdio. h> # include <stdlib. h> # include "memglobal. h "/** global memory count, check whether the memory exceeded */int main (int argc, char * argv []) {// enable global memory count mg_start (); int * p = malloc (16); p = calloc (12, 2); * p = 154; puts ("that's it! "); P = realloc (NULL, 6); puts (" test this! "); Return 0 ;}
The test result is as follows:
The final log is
Good. Here we have explained and implemented the memory global detection technique. It is very easy to use.
The focus is on understanding the above two methods of thinking. Haha, isn't it amazing to find memory leaks, memory out-of-bounds, and memory leak monitoring.
Development and code writing are very simple, but it is very difficult to convert to productivity, and more capabilities may be needed to convert them together.
Postscript
Errors are inevitable. You are welcome to join us ~~. Hope to get up early and get up early.