Apr 8, 2014
Technology###Full Circle C 7
####Example
Following is the origin ifstat.c, this program will list the net-interface payloads, and it will print out the net interface statistics every 2 seconds, but notice this program have several bugs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef unsigned long long ull;
int parseDevFile(const char * iface, ull *bRx, ull *pRx, ull *bTx, ull *pTx);
void dumpInterfaceUsage(const char * iface);
int parseDevFile(const char * iface, ull *bRx, ull *pRx, ull *bTx, ull *pTx)
{
FILE * fp = NULL;
char * line = NULL;
unsigned int len = 0;
fp = fopen("/proc/net/dev", "r");
if(fp == NULL)
{
return -1;
}
while(getline(&line, &len, fp) != -1)
{
if(strstr(line, iface) != NULL)
{
sscanf(strstr(line, ":")+1, "%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu", bRx, pRx, bTx, pTx);
}
}
fclose(fp);
free(line);
return 0;
}
void dumpInterfaceUsage(const char * iface)
{
ull ifaceBRxOld = 0, ifaceBTxOld = 0, ifacePRxOld = 0, ifacePTxOld = 0;
ull ifaceBRxNew = 0, ifaceBTxNew = 0, ifacePRxNew = 0, ifacePTxNew = 0;
const int SLEEP_TIME = 2;
if(parseDevFile(iface, &ifaceBRxOld, &ifacePRxOld, &ifaceBTxOld, &ifacePTxOld) == -1) return;
sleep(SLEEP_TIME);
while(1)
{
if(parseDevFile(iface, &ifaceBRxNew, &ifacePRxNew, &ifaceBTxNew, &ifacePTxNew) == -1) return;
printf("%s In: %8.2f kbytes/s %5llu P/s Out: %8.2f kbytes/s %5llu P/s\n", iface,
(ifaceBRxNew - ifaceBRxOld)/(SLEEP_TIME *1024.0),
(ifacePRxNew - ifacePRxOld)/(SLEEP_TIME),
(ifaceBTxNew - ifaceBTxOld)/(SLEEP_TIME *1024.0),
(ifacePTxNew - ifacePTxOld)/(SLEEP_TIME));
ifaceBRxOld = ifaceBRxNew;
ifaceBTxOld = ifaceBTxNew;
ifacePRxOld = ifacePRxNew;
ifacePTxOld = ifacePTxNew;
sleep(SLEEP_TIME);
}
}
int main(int argc, char **argv)
{
if(argc != 2)
{
printf("Usage: %s interfacename\n", argv[0]);
return 1;
}
dumpInterfaceUsage(argv[1]);
return 0;
}
Running result:
[root@localhost C7]# ./ifstat eth0
eth0 In: 0.24 kbytes/s 2 P/s Out: 0.25 kbytes/s 1 P/s
eth0 In: 0.32 kbytes/s 4 P/s Out: 0.97 kbytes/s 3 P/s
eth0 In: 1.29 kbytes/s 13 P/s Out: 5.06 kbytes/s 13 P/s
eth0 In: 0.06 kbytes/s 1 P/s Out: 0.08 kbytes/s 0 P/s
####Bugs
Ok, now let’s see its bug:
#enable the unlimited:
[root@localhost C7]# ulimit -c unlimited
#Get the core file:
[root@localhost C7]# ./ifstat b
Segmentation fault (core dumped)
####Debugging
[root@localhost C7]# ls -l -h core*
-rw------- 1 root root 272K Oct 14 06:53 core.3961
#Use gdb for anlysing the corefile:
[root@localhost C7]# gdb ifstat core.3961
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./ifstat b'.
Program terminated with signal 11, Segmentation fault.
[New process 3961]
#0 0x00b6f957 in rawmemchr () from /lib/libc.so.6
Seems the corefile is useless, this because the error is not derived from our own code, but rather from the library. Run gdb for anlysing the ./ifstat b
[root@localhost C7]# gdb ./ifstat
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) run b
Starting program: /root/code/C7/ifstat b
Program received signal SIGSEGV, Segmentation fault.
0x00b6f957 in rawmemchr () from /lib/libc.so.6
(gdb) break parseDevFile
Breakpoint 1 at 0x804854a: file ifstat.c, line 10.
(gdb) run b
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/code/C7/ifstat b
Breakpoint 1, parseDevFile (iface=0xbfe52b5e "b", bRx=0xbfe50f80, pRx=0xbfe50f70, bTx=0xbfe50f78, pTx=0xbfe50f68) at ifstat.c:10
10 FILE * fp = NULL;
(gdb) step
11 char * line = NULL;
(gdb)
12 unsigned int len = 0;
(gdb)
13 fp = fopen("/proc/net/dev", "r");
(gdb) print fp
$1 = (FILE *) 0x0
(gdb) step
14 if(fp == NULL)
(gdb) step
18 while(getline(&line, &len, fp) != -1)
(gdb) display line
1: line = 0x0
(gdb) step
20 if(strstr(line, iface) != NULL)
1: line = 0x9730170 "Inter-| Receive", ' ' <repeats 48 times>, "| Transmit\n"
(gdb) step
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9730170 "Inter-| Receive", ' ' <repeats 48 times>, "| Transmit\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9730170 " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
(gdb)
22 sscanf(strstr(line, ":")+1, "%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu", bRx, pRx, bTx, pTx);
1: line = 0x9730170 " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x00b6f957 in rawmemchr () from /lib/libc.so.6
(gdb)
We found another bug, also we can see ./ifstat dba
[root@localhost C7]# gdb ./ifstat
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) run dba
Starting program: /root/code/C7/ifstat dba
dba In: 0.00 kbytes/s 0 P/s Out: 0.00 kbytes/s 0 P/s
dba In: 0.00 kbytes/s 0 P/s Out: 0.00 kbytes/s 0 P/s
Program received signal SIGINT, Interrupt.
0x00ef3402 in __kernel_vsyscall ()
(gdb) break parseDevFile
Breakpoint 1 at 0x804854a: file ifstat.c, line 10.
(gdb) run dba
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/code/C7/ifstat dba
Breakpoint 1, parseDevFile (iface=0xbf81bb5c "dba", bRx=0xbf81ad40, pRx=0xbf81ad30, bTx=0xbf81ad38, pTx=0xbf81ad28) at ifstat.c:10
10 FILE * fp = NULL;
(gdb) step
11 char * line = NULL;
(gdb) step
12 unsigned int len = 0;
(gdb) step
13 fp = fopen("/proc/net/dev", "r");
(gdb) step
14 if(fp == NULL)
(gdb) step
18 while(getline(&line, &len, fp) != -1)
(gdb) display line
1: line = 0x0
(gdb) step
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 "Inter-| Receive", ' ' <repeats 48 times>, "| Transmit\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "Inter-| Receive", ' ' <repeats 48 times>, "| Transmit\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " lo: 4684910 2267 0 0 0 0 0 0 4684910 2267 0 0 0 0 0 0\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " lo: 4684910 2267 0 0 0 0 0 0 4684910 2267 0 0 0 0 0 0\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " eth0: 5135043 75928 0 0 0 0 0 0 15204045 129941 0 0 0 0 0 0\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " eth0: 5135043 75928 0 0 0 0 0 0 15204045 129941 0 0 0 0 0 0\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
25 fclose(fp);
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
26 free(line);
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
27 return 0;
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
28 }
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
dumpInterfaceUsage (iface=0xbf81bb5c "dba") at ifstat.c:36
36 sleep(SLEEP_TIME);
(gdb)
39 if(parseDevFile(iface, &ifaceBRxNew, &ifacePRxNew, &ifaceBTxNew, &ifacePTxNew) == -1) return;
(gdb)
Breakpoint 1, parseDevFile (iface=0xbf81bb5c "dba", bRx=0xbf81ad20, pRx=0xbf81ad10, bTx=0xbf81ad18, pTx=0xbf81ad08) at ifstat.c:10
10 FILE * fp = NULL;
1: line = 0xaf5ca0 ""
(gdb)
11 char * line = NULL;
1: line = 0xaf5ca0 ""
(gdb)
12 unsigned int len = 0;
1: line = 0x0
(gdb)
13 fp = fopen("/proc/net/dev", "r");
1: line = 0x0
(gdb)
14 if(fp == NULL)
1: line = 0x0
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x0
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 "Inter-| Receive", ' ' <repeats 48 times>, "| Transmit\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 "Inter-| Receive", ' ' <repeats 48 times>, "| Transmit\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " lo: 4684910 2267 0 0 0 0 0 0 4684910 2267 0 0 0 0 0 0\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " lo: 4684910 2267 0 0 0 0 0 0 4684910 2267 0 0 0 0 0 0\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " eth0: 5141021 76010 0 0 0 0 0 0 15217535 130042 0 0 0 0 0 0\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " eth0: 5141021 76010 0 0 0 0 0 0 15217535 130042 0 0 0 0 0 0\n"
(gdb)
20 if(strstr(line, iface) != NULL)
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
18 while(getline(&line, &len, fp) != -1)
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
25 fclose(fp);
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
26 free(line);
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
27 return 0;
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
28 }
1: line = 0x9101170 " sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
(gdb)
dumpInterfaceUsage (iface=0xbf81bb5c "dba") at ifstat.c:40
40 printf("%s In: %8.2f kbytes/s %5llu P/s Out: %8.2f kbytes/s %5llu P/s\n", iface,
(gdb)
dba In: 0.00 kbytes/s 0 P/s Out: 0.00 kbytes/s 0 P/s
####Conclusion:
And now we can get the reason, the ./ifstat b is because we reached the line2 of the /proc/net/dev, it has b for “bytes”.
./ifstat dba always print 0 because we don’t have this equipment at all !
####Correcting
So the corrected code is listed as following:
int parseDevFile(const char * iface, ull *bRx, ull *pRx, ull *bTx, ull *pTx)
{
FILE * fp = NULL;
char * line = NULL;
unsigned int len = 0;
short int exists = 0;
fp = fopen("/proc/net/dev", "r");
if(fp == NULL)
{
return -1;
}
while(getline(&line, &len, fp) != -1)
{
if(strstr(line, iface) != NULL)
{
if(strstr(line, ":") != NULL)
{
sscanf(strstr(line, ":")+1, "%llu%llu%*u%*u%*u%*u%*u%*u%llu%llu", bRx, pRx, bTx, pTx);
exists = 1;
}
}
}
fclose(fp);
free(line);
if( exists != 1)
{
fprintf(stderr, "Your device %s is not in the file /proc/net/dev!\n", iface);
exit(2);
}
return 0;
}
Now run it and the result is listed as:
[root@localhost C7]# ./ifstat_upgrade b
Your device b is not in the file /proc/net/dev!
[root@localhost C7]# ./ifstat_upgrade bba
Your device bba is not in the file /proc/net/dev!
[root@localhost C7]# ./ifstat_upgrade eth0
eth0 In: 0.03 kbytes/s 0 P/s Out: 0.00 kbytes/s 0 P/s
eth0 In: 0.03 kbytes/s 0 P/s Out: 0.08 kbytes/s 0 P/s
Apr 8, 2014
Technology###Full Circle C 6
####Using valgrid for memory check
See www.valgrind.org for more information for using the valgrind available tools.
memcheck is the main topic in this chapter.
this tool override libc calls that deal with handling memory. And it will do some bookkeeping. is all memory given back to the system, and is all the allocated memory still reachable?
#include <stdio.h>
#include <stdlib.h>
void leak()
{
char *ptr = malloc(10);
printf("malloc(10) points to: %p\n", ptr);
}
int main()
{
int i = 0;
for(i = 0; i<10; i++)
{
leak();
}
char *ptr = malloc(15);
printf("malloc(15) in main: %p\n", ptr);
while(1){}
return 0;
}
The result shows:
valgrind --leak-check=full --show-reachable=yes ./memleak
==2144== Memcheck, a memory error detector.
==2144== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==2144== Using LibVEX rev 1658, a library for dynamic binary translation.
==2144== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==2144== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==2144== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==2144== For more details, rerun with: -v
==2144==
malloc(10) points to: 0x4022028
malloc(10) points to: 0x4022068
malloc(10) points to: 0x40220a8
malloc(10) points to: 0x40220e8
malloc(10) points to: 0x4022128
malloc(10) points to: 0x4022168
malloc(10) points to: 0x40221a8
malloc(10) points to: 0x40221e8
malloc(10) points to: 0x4022228
malloc(10) points to: 0x4022268
malloc(15) in main: 0x40222a8
==2144==
==2144== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
==2144== malloc/free: in use at exit: 115 bytes in 11 blocks.
==2144== malloc/free: 11 allocs, 0 frees, 115 bytes allocated.
==2144== For counts of detected errors, rerun with: -v
==2144== searching for pointers to 11 not-freed blocks.
==2144== checked 46,792 bytes.
==2144==
==2144== 15 bytes in 1 blocks are still reachable in loss record 1 of 2
==2144== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==2144== by 0x8048419: main (leak.c:17)
==2144==
==2144==
==2144== 100 bytes in 10 blocks are definitely lost in loss record 2 of 2
==2144== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==2144== by 0x80483C5: leak (leak.c:6)
==2144== by 0x8048403: main (leak.c:15)
==2144==
==2144== LEAK SUMMARY:
==2144== definitely lost: 100 bytes in 10 blocks.
==2144== possibly lost: 0 bytes in 0 blocks.
==2144== still reachable: 15 bytes in 1 blocks.
==2144== suppressed: 0 bytes in 0 blocks.
If we change the code into following, this means valgrid won’t interpret the output, so this will let the tracked memory add 10
#include <stdio.h>
#include <stdlib.h>
void leak()
{
char *ptr = malloc(10);
printf("malloc(10) points to: %p\n", ptr);
}
int main()
{
int i = 0;
for(i = 0; i<10; i++)
{
leak();
}
char *ptr = malloc(15);
printf("malloc(15) in main: %p\n", ptr);
//while(1){}
return 0;
}
Compile and verify:
gcc -Wall -g leak1.c -o memleak1
View the valgrind result:
valgrind --leak-check=full --show-reachable=yes ./memleak1
==2190== Memcheck, a memory error detector.
==2190== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==2190== Using LibVEX rev 1658, a library for dynamic binary translation.
==2190== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==2190== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==2190== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==2190== For more details, rerun with: -v
==2190==
malloc(10) points to: 0x4022028
malloc(10) points to: 0x4022068
malloc(10) points to: 0x40220a8
malloc(10) points to: 0x40220e8
malloc(10) points to: 0x4022128
malloc(10) points to: 0x4022168
malloc(10) points to: 0x40221a8
malloc(10) points to: 0x40221e8
malloc(10) points to: 0x4022228
malloc(10) points to: 0x4022268
malloc(15) in main: 0x40222a8
==2190==
==2190== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
==2190== malloc/free: in use at exit: 115 bytes in 11 blocks.
==2190== malloc/free: 11 allocs, 0 frees, 115 bytes allocated.
==2190== For counts of detected errors, rerun with: -v
==2190== searching for pointers to 11 not-freed blocks.
==2190== checked 46,796 bytes.
==2190==
==2190== 15 bytes in 1 blocks are definitely lost in loss record 1 of 2
==2190== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==2190== by 0x8048419: main (leak1.c:17)
==2190==
==2190==
==2190== 100 bytes in 10 blocks are definitely lost in loss record 2 of 2
==2190== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==2190== by 0x80483C5: leak (leak1.c:6)
==2190== by 0x8048403: main (leak1.c:15)
==2190==
==2190== LEAK SUMMARY:
==2190== definitely lost: 115 bytes in 11 blocks.
==2190== possibly lost: 0 bytes in 0 blocks.
==2190== still reachable: 0 bytes in 0 blocks.
==2190== suppressed: 0 bytes in 0 blocks.
####exercise 1:
vmstat is a tool which report system usage statistics, use strace to figure out which /proc/file(s) it uses to generate its output
execve("/usr/bin/vmstat", ["vmstat"], [/* 29 vars */]) = 0
brk(0) = 0x96b7000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=95416, ...}) = 0
mmap2(NULL, 95416, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f80000
close(3) = 0
open("/lib/libproc-3.2.7.so", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320c\304\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=54212, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f7f000
mmap2(0xc44000, 133592, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xc44000
mmap2(0xc51000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xc) = 0xc51000
mmap2(0xc52000, 76248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xc52000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320?\261\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1606808, ...}) = 0
mmap2(0xafe000, 1324452, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xafe000
mmap2(0xc3c000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13e) = 0xc3c000
mmap2(0xc3f000, 9636, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xc3f000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f7e000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7f7e6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xc3c000, 8192, PROT_READ) = 0
mprotect(0xaf5000, 4096, PROT_READ) = 0
munmap(0xb7f80000, 95416) = 0
uname({sys="Linux", node="localhost.localdomain", ...}) = 0
brk(0) = 0x96b7000
brk(0x96d8000) = 0x96d8000
open("/proc/stat", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f97000
read(3, "cpu 14886 15300 97152 608490 41"..., 4096) = 693
read(3, "", 4096) = 0
close(3) = 0
munmap(0xb7f97000, 4096) = 0
ioctl(1, TIOCGWINSZ, {ws_row=36, ws_col=115, ws_xpixel=0, ws_ypixel=0}) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f97000
write(1, "procs -----------memory---------"..., 82procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
) = 82
write(1, " r b swpd free buff cach"..., 81 r b swpd free buff cache si so bi bo in cs us sy id wa st
) = 81
open("/proc/meminfo", O_RDONLY) = 3
lseek(3, 0, SEEK_SET) = 0
read(3, "MemTotal: 897068 kB\nMemFre"..., 1023) = 771
open("/proc/stat", O_RDONLY) = 4
read(4, "cpu 14886 15300 97153 608490 41"..., 65535) = 693
open("/proc/vmstat", O_RDONLY) = 5
lseek(5, 0, SEEK_SET) = 0
read(5, "nr_anon_pages 29682\nnr_mapped 13"..., 1023) = 803
write(1, " 0 0 120 16980 32852 67407"..., 81 0 0 120 16980 32852 674076 0 0 228 223 1040 432 4 13 78 5 0
) = 81
exit_group(0) = ?
From the above output, we can see, it access /proc/stat and /proc/vmstat for output message.
####exercise 2
Repeat the ltrace /strace example on wget with ivalid URL, TBD
####exercise 3
Does valgrind automatically trace child process?
#include <stdio.h>
#include <stdlib.h>
/* For using fork() */
#include <sys/types.h>
#include <unistd.h>
/* Using errono */
#include <errno.h>
#include <string.h>
void leak()
{
char *ptr = malloc(10);
printf("malloc(10) points to: %p\n", ptr);
}
int main(void)
{
pid_t child;
/* Parent do leak() */
int i = 0;
for(i = 0; i<10; i++)
{
leak();
}
/* Now fork a child process */
if((child = fork()) < 0) {
fprintf(stderr, "fork of child failed: %s\n", strerror(errno));
return 1;
}
else if(child == 0) {
printf("Now its in child process\n");
sleep(2);
}
else {
// parent will exit immediately !
printf("Parent will exit!\n");
sleep(1);
return 0;
}
// Only Child comes here
printf("Only child comes here!\n");
for(i = 0; i<10; i++)
{
leak();
}
return 0;
}
We use following command for tracing the output:
[root@localhost code]# valgrind --leak-check=full --show-reachable=yes ./memleak_fork
==2561== Memcheck, a memory error detector.
==2561== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==2561== Using LibVEX rev 1658, a library for dynamic binary translation.
==2561== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==2561== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==2561== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==2561== For more details, rerun with: -v
==2561==
malloc(10) points to: 0x4022028
malloc(10) points to: 0x4022068
malloc(10) points to: 0x40220a8
malloc(10) points to: 0x40220e8
malloc(10) points to: 0x4022128
malloc(10) points to: 0x4022168
malloc(10) points to: 0x40221a8
malloc(10) points to: 0x40221e8
malloc(10) points to: 0x4022228
malloc(10) points to: 0x4022268
Now its in child process
Parent will exit!
==2561==
==2561== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
==2561== malloc/free: in use at exit: 100 bytes in 10 blocks.
==2561== malloc/free: 10 allocs, 0 frees, 100 bytes allocated.
==2561== For counts of detected errors, rerun with: -v
==2561== searching for pointers to 10 not-freed blocks.
==2561== checked 46,796 bytes.
==2561==
==2561== 100 bytes in 10 blocks are definitely lost in loss record 1 of 1
==2561== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==2561== by 0x8048515: leak (fork.c:15)
==2561== by 0x8048553: main (fork.c:26)
==2561==
==2561== LEAK SUMMARY:
==2561== definitely lost: 100 bytes in 10 blocks.
==2561== possibly lost: 0 bytes in 0 blocks.
==2561== still reachable: 0 bytes in 0 blocks.
==2561== suppressed: 0 bytes in 0 blocks.
[root@localhost code]# Only child comes here!
malloc(10) points to: 0x40222a8
malloc(10) points to: 0x40222e8
malloc(10) points to: 0x4022328
malloc(10) points to: 0x4022368
malloc(10) points to: 0x40223a8
malloc(10) points to: 0x40223e8
malloc(10) points to: 0x4022428
malloc(10) points to: 0x4022468
malloc(10) points to: 0x40224a8
malloc(10) points to: 0x40224e8
==2562==
==2562== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
==2562== malloc/free: in use at exit: 200 bytes in 20 blocks.
==2562== malloc/free: 20 allocs, 0 frees, 200 bytes allocated.
==2562== For counts of detected errors, rerun with: -v
==2562== searching for pointers to 20 not-freed blocks.
==2562== checked 46,796 bytes.
==2562==
==2562== 200 bytes in 20 blocks are definitely lost in loss record 1 of 1
==2562== at 0x40053C0: malloc (vg_replace_malloc.c:149)
==2562== by 0x8048515: leak (fork.c:15)
==2562== by 0x8048553: main (fork.c:26)
==2562==
==2562== LEAK SUMMARY:
==2562== definitely lost: 200 bytes in 20 blocks.
==2562== possibly lost: 0 bytes in 0 blocks.
==2562== still reachable: 0 bytes in 0 blocks.
==2562== suppressed: 0 bytes in 0 blocks.
From the above output, we can see valgrid also tracked the child process’s memory usage.
Apr 8, 2014
Technology###Full Circle C 5
####Callback
Use Call Back function for implementing a calculator:
#include <stdio.h>
int minus(int a, int b)
{
return a-b;
}
int add(int a, int b)
{
return a+b;
}
int multiply(int a, int b)
{
return a*b;
}
int divide(int a, int b)
{
return a/b;
}
typedef int (*mathFun)(int, int);
struct operator
{
char c;
mathFun f;
};
int main()
{
struct operator functs[4];
functs[0].c = '-'; functs[0].f=−
functs[1].c = '+'; functs[1].f=&add;
functs[2].c = '*'; functs[2].f=&multiply;
functs[3].c = '/'; functs[3].f=÷
while(1)
{
int a,b,i;
char c;
printf("Enter a:\n");
scanf("%d", &a);
printf("Enter b:\n");
scanf("%d", &b);
printf("Enter the operator:\n");
scanf("%c", &c);
scanf("%c", &c);
i = 0;
while(i<4)
{
if(functs[i].c==c)
{
printf("Result:%d\n", functs[i].f(a,b));
break;
}
i++;
}
if(i == 4)
{
printf("Unkown operator:%c\n", c);
}
}
return 0;
}
####Exercise 1
Modify the application to operate on floating point numbers instead of integers.
#include <stdio.h>
float minus(float a, float b)
{
return a-b;
}
float add(float a, float b)
{
return a+b;
}
float multiply(float a, float b)
{
return a*b;
}
float divide(float a, float b)
{
return a/b;
}
typedef float (*mathFun)(float, float);
struct operator
{
char c;
mathFun f;
};
int main()
{
struct operator functs[4];
functs[0].c = '-'; functs[0].f=−
functs[1].c = '+'; functs[1].f=&add;
functs[2].c = '*'; functs[2].f=&multiply;
functs[3].c = '/'; functs[3].f=÷
while(1)
{
int i;
float a,b;
char c;
printf("Enter a:\n");
scanf("%f", &a);
printf("Enter b:\n");
scanf("%f", &b);
printf("Enter the operator:\n");
scanf("%c", &c);
scanf("%c", &c);
i = 0;
while(i<4)
{
if(functs[i].c==c)
{
printf("Result:%f\n", functs[i].f(a,b));
break;
}
i++;
}
if(i == 4)
{
printf("Unkown operator:%c\n", c);
}
}
return 0;
}
####Exercise 2
Extend the calculator with the possibility for the user to enter ‘q’ for quit
#include <stdio.h>
int minus(int a, int b)
{
return a-b;
}
int add(int a, int b)
{
return a+b;
}
int multiply(int a, int b)
{
return a*b;
}
int divide(int a, int b)
{
return a/b;
}
typedef int (*mathFun)(int, int);
struct operator
{
char c;
mathFun f;
};
int main()
{
struct operator functs[4];
functs[0].c = '-'; functs[0].f=−
functs[1].c = '+'; functs[1].f=&add;
functs[2].c = '*'; functs[2].f=&multiply;
functs[3].c = '/'; functs[3].f=÷
char q;
do
{
int a,b,i;
char c;
printf("Enter a:\n");
scanf("%d", &a);
printf("Enter b:\n");
scanf("%d", &b);
printf("Enter the operator:\n");
scanf("%c", &c);
scanf("%c", &c);
i = 0;
while(i<4)
{
if(functs[i].c==c)
{
printf("Result:%d\n", functs[i].f(a,b));
break;
}
i++;
}
if(i == 4)
{
printf("Unkown operator:%c\n", c);
}
printf("Enter q for quit! Others for continue\n");
scanf("%c",&q);
scanf("%c",&q);
}
while(q != 'q');
return 0;
}
####Exercise 4
Modify the application that, instead of entering characters, the user is able to enter “5 plus 6” or “6 minus 5”. In order to do this, you will need to adapt the structure to hold a string as the operator, and, instead of reading a character, you will need to read a string. Extra credit if you manage to do this without buffer overrun issues (see man getline) and memory leaks.
#include <stdio.h>
#include <string.h>
int minus(int a, int b)
{
return a-b;
}
int add(int a, int b)
{
return a+b;
}
int multiply(int a, int b)
{
return a*b;
}
int divide(int a, int b)
{
return a/b;
}
typedef int (*mathFun)(int, int);
struct operator
{ char c[20];
mathFun f;
};
int main()
{
struct operator functs[4];
strcpy(functs[0].c, "minus");
functs[0].f=−
strcpy(functs[1].c, "add");
functs[1].f=&add;
strcpy(functs[2].c, "mul");
functs[2].f=&multiply;
strcpy(functs[3].c, "div");
functs[3].f=÷
while(1)
{
int a,b,i;
char c[20];
printf("Enter a:\n");
scanf("%d", &a);
printf("Enter b:\n");
scanf("%d", &b);
printf("Enter the operator:\n");
scanf("%s", c);
i = 0;
while(i<4)
{
int result = strcmp(functs[i].c, c);
if(result == 0)
{
printf("Result is :%d\n", functs[i].f(a,b));
break;
}
i++;
}
if(i == 4)
{
printf("Unkown operator:%s\n", c);
}
}
return 0;
}
Apr 7, 2014
Technology###Full Circle C 3
####Exercise 1
Collect all the code snippets on this page and turn them into the working program
Pointer:
#include <stdio.h>
int main(void)
{
int anInt = 5;
int *anIntPointer = &anInt;
printf("Address: %p Value: %d \n", &anInt, anInt);
printf("Address of Pointer: %p Address: %p Value: %d\n", &anIntPointer, anIntPointer, *anIntPointer);
printf("Size of pointer: %d, size of int: %d\n", sizeof(anIntPointer), sizeof(anInt));
return 0;
}
array.c
#include <stdio.h>
int main(void)
{
int i;
int anIntArray[5] = {10, 20, 30, 40, 50};
printf("Address of Array: %p \n", &anIntArray);
printf("Size of Array: %d\n", sizeof(anIntArray));
for(i = 0; i<sizeof(anIntArray)/sizeof(int); i++)
{
printf("Index: %x Address: %p Value: %d, Value: %d\n", i, &anIntArray[i], anIntArray[i], *(anIntArray+i));
}
return 0;
}
string:
#include <stdio.h>
#include <string.h>
int main()
{
int i;
char aChar = 'c';
char * aString = "Hello";
printf("Address: %p value: %c size: %d\n", &aChar, aChar, sizeof(aChar));
printf("Address of the string: %p\n", &aString);
printf("Size of String: %d\n", strlen(aString));
printf("Value: %s\n", aString);
for(i = 0; i<=strlen(aString); i++)
{
printf("Index:%x Address: %p, Value:%c\n", i, &aString[i], aString[i]);
}
return 0;
}
Structure:
#include <stdio.h>
struct aStruct_def
{
int intMember;
int * intPointer;
char charMember;
char ** stringPointer;
};
int main(void)
{
struct aStruct_def aStruct;
struct aStruct_def *aStructPointer;
int anInt = 5;
char *aString = "Hello";
printf("Address: %p Size: %d\n", &aStruct, sizeof(struct aStruct_def));
printf("%p %p %p %p\n", &aStruct.intMember, &aStruct.intPointer, &aStruct.charMember, &aStruct.stringPointer);
aStruct.intMember = 6;
aStruct.intPointer = &anInt;
aStruct.charMember = 'k';
aStruct.stringPointer = &aString;
aStructPointer = &aStruct;
printf("Member of struct: %d\n", (*aStructPointer).intMember);
printf("Member of struct: %d\n", *(*aStructPointer).intPointer);
printf("Member of struct: %d\n", aStructPointer->intMember);
printf("Member of struct: %d\n", *aStructPointer->intPointer);
printf("Member of struct: %s\n", *aStructPointer->stringPointer);
return 0;
}
####Exercise 2
Implement strlen yourself use a while() loop:
#include <stdio.h>
int mystrlen(char *strings)
{
int i = 0;
while(strings[i] != '\0')
{
i++;
}
return i;
}
int main()
{
char *a = "Hello World";
printf("%s 's length is %d\n", a, mystrlen(a));
return 0;
}
###Exercise 3
A C application typically has ‘int main(int argc, char **argv)’ as it’s main prototype, here argc contains the number of strings passed to the application, and argc is an array of argc strings. Write a small application which prints all arguments given to the application. What is stored in argv[0] ?
#include <stdio.h>
int main(int argc, char **argv)
{
int i = 0;
for(i = 0; i<argc; i++)
{
printf("arg %d is %s\n", i, argv[i]);
}
return 0;
}
Apr 7, 2014
Technology###Programming In C
intermediate: 中级的
hereby: 特此
scary: 恐慌的,提心吊胆的
de facto (法),事实上的
span: 跨越
interpreted: 可交互的
fanatic: 狂热者
novice: 新手,入门者
concrete: 实际的
prime number: 素数,质数
ternary: 三重的,三元的
intrusive: 侵入的,打扰的
grind: 磨难,磨碎,折磨
confessed: 坦白的
scary: 提心吊胆的,胆小的
apropos: 恰好的
grasp: 掌握
instalment: 分期付款的
gibberish: 乱语,快速而不清楚的话语
condense: 电容器