You are on page 1of 47

Advanced C - Workshop

A L
TI
E N
I D By

NF Madheswaran D
C O
R O
P
WI Version: <1.3>
Date: < 23/10/2006>
Introduction

§ Pre-requisites
• Basic C knowledge (Not covered here)
• Familiarity with Unix environment (basic unix commands, user
knowledge on Vi or Emacs editors). (Not covered here)
• Alignment & Padding issues.
• Good understanding about pointers.
• Good understanding about bitwise operators
A L
TI
§ Advanced Topics N
• E
Handy Expressions involving bitDwise operations
• Stack frames à What happens F Iduring function calls
• Variable arguments à How O Nis it implemented?
• C
Dynamic memory allocation à A sample design of malloc/free
• R O
P
Executable File content
I
W
Wipro confidential 2
Alignment & Padding

§ For today’s session, assume following sizes and study the following program
• Char: 1 byte
• Int: 4 bytes
• Short: 2 bytes

typedef struct
{
char name[30];
int empno;
int salary;

} EmpRec, * EmpRecPtr;

A L
main()
{
T I
int x = 1;
E N
char y = 2;
I D
int z = 3;
EmpRec abc; N F
EmpRecPtr empr = &abc;
C O
R O
printf(“Sizes: int=%d, char=%d, EmpRec=%d, EmpRecPtr=%d\n”, sizeof(x), sizeof(y),
sizeof(abc), sizeof(empr));
P
WI
printf(“Address: &x=%p, &y=%p, &z=%p, &abc=%p, &empr=%p\n”, &x, &y, &z, &abc,
&empr);
printf("Address: &abc.name=%p, &abc.empno=%p, &abc.salary=%p\n", &abc.name,
&abc.empno, &abc.salary); }
Wipro confidential 3
Alignment & Padding

§ For today’s session, assume following sizes and study the following program
• Char: 1 byte
• Int: 4 bytes
• Short: 2 bytes Sizes: int=4, char=1, EmpRec=40, EmpRecPtr=4
typedef struct Address: &x=0xbffffb3c, &y=0xbffffb3b, &z=0xbffffb34,
{ &abc=0xbffffb00, &empr=0xbffffafc
char name[30];
int empno;
Address: &abc.name=0xbffffb00,
int salary; &abc.empno=0xbffffb20, &abc.salary=0xbffffb24

} EmpRec, * EmpRecPtr;

main() A L
{
T I
int x = 1;
E N
char y = 2;
int z = 3; I D
EmpRec abc;
N F
EmpRecPtr empr = &abc;
C O
O
printf(“Sizes: int=%d, char=%d, EmpRec=%d, EmpRecPtr=%d\n”, sizeof(x), sizeof(y),
R
sizeof(abc), sizeof(empr));
P
WI
printf(“Address: &x=%p, &y=%p, &z=%p, &abc=%p, &empr=%p\n”, &x, &y, &z, &abc,
&empr);
printf("Address: &abc.name=%p, &abc.empno=%p, &abc.salary=%p\n", &abc.name,
&abc.empno, &abc.salary);}
Wipro confidential 4
Memory view

&(abc.name)
&(abc.salary) &(abc.empno)

typedef struct b00 | | |


Lower
{ | | |
Memory
char name[30]; | | |
int empno;
int salary; | | |
} EmpRec, *EmpRecPtr; | | |

Stack grows | | |
main()
{ | | |
int x = 1; this way
| | p | p b1f
char y = 2;
int z = 3; L
b20
Ab24
| | |

TI
EmpRec abc; | | | b27
EmpRecPtr empr = &abc; p | p | p | p

E N
Higher
b28
p | p | p | p
printf("Sizes: int=%d, char=%d, EmpRec=%d,
DMemory

FI
EmpRecPtr=%d\n", sizeof(x), sizeof(y), p | p | p | p
sizeof(abc), sizeof(empr)); 3 | 0 | 0 | 0 b37
printf("Address: &x=%p, &y=%p, &z=%p,
&abc=%p, &empr=%p\n", &x, &y, &z, &abc,
O N b34
b38 p | p | p | 2 b3b
&empr);
C b3c 1 | 0 | 0 | 0 b3f
O
printf("Address: &abc.name=%p,

P R
&abc.empno=%p, &abc.salary=%p\n",
&abc.name, &abc.empno, &abc.salary);

WI
}
&z &x &y

Wipro confidential 5
Alignment & Padding

§ Memory address of a variable will align with their size.


§ In some architectures, unaligned access can result in SIGBUS.
• In some cases, the memory access will be split
§ This is applicable for global variables, local variables,
arguments passed to function and structure/union as well.
§ To ensure address is correctly aligned, padding is done. Keep
this in mind: L A
• To calculate the size of structure/union T I
N
• Beware if this is mapped to a set ofEregisters.
• Assembly/C intermixing – Suitable I D mask & shifting may needed
• Bit fields doesn’t have suchON
F
alignment requirements
• Compiler generates codeCwith masks & shifts to handle this.
R O
I P
W
Wipro confidential 6
SIGBUS or SPLIT ACCESS EXAMPLE

main()
{
char x = 10;
char y = 20;
int *p = &y;
printf(“&y=%p &p=%p\n”, &y, &p);
printf(“%d\n”, (*p) & 0xff); /* SIGBUS or unaligned split access */
} L
A
T I
E N
ID
N F
CO
R O
P
WI
Wipro confidential 7
Alignment & Padding

§ Assume a H/W device is memory mapped on the system bus


• Occupies a address space of 16 bytes where 8 registers are located
• Three 32 bit Registers(CNTL1, CNTL2, CNTL3, in that order)
• Four 8 bit Registers(STAT1, STAT2, STAT3, and ERR in that order)
• Assume it is located at 0x2000 in the memory map
• A structure can be defined to map this
struct hw_device {
unsigned int cntl1;
unsigned int cntl2;
unsigned int cntl3;
unsigned char stat1;
unsigned char stat2;
A L
unsigned char stat3;
T I
unsigned char err;
} *my_hw_device; E N
I D
F
my_hw_device_ptr = (struct hw_device *) (0x2000);
N
O
The registers can be accessed as my_hw_device->cntl1, my_hw_device->err and so on.
C to device driver writers, OS developers
Simplifies access to device registers, useful .
• Should be careful about any
R O padding for alignment restrictions
P
WI
Wipro confidential 8
Example – Where padding causes trouble

Register sequence:
Two 32 bit Registers(CNTL1, CNTL2, in that order)
Three 8 bit Registers(STAT1, STAT2, STAT3, in that order)
One 32 bit register CNTL3
One 8 bit register ERR
Bad structure that can cause trouble:
typedef struct hw_device {
unsigned int cntl1;
unsigned int cntl2;
unsigned char stat1; A L
unsigned char stat2; T I
unsigned char stat3; E N
unsigned int cntl3; I D
unsigned char err; N F
} MYDEVICE, *MYDEVICE_PTR;CO

R O
P
WI
Wipro confidential 9
Pointers – Basics

§ Pointer holds address of a variable.


int x = 10;
int *p = &x;
printf(“&x=%p, p=%p, x=%d, *p=%d\n”, &x, p, x, *p);
• Output:
&x=0x22cce4, p=0x22cce4, x=10, *p=10
§ Then why do you need a pointer?
& cannot be used as a “lvalue”
&x = p; /* this is not a legal statement */
§ Even const pointers doesn’t have lvalue
Int * const p = x;
p = p + 1; /* illegal statement */

const int *p = x;

L
*p = 10; /* illegal statement */
§ Arrays and Pointers
char a[10]=“Hello”;
I A
char *str = a;
printf(“%s %s\n”, a, str);
N T
printf(“%c %c %c %c\n”, a[1], str[1], 1[str], 1[a]);
DE
I
printf(“%p %p %p %p\n”, a, str, &a[1], str+1);

F
Output:
Hello Hello
eeee
O N
0x22ccd0 0x22ccd0 0x22ccd1 0x22ccd1 C
§
• Yes and No.
R O
Then pointers and arrays be interchangeably used?

P
WI
Wipro confidential 10
Pointers – Basics

§ Arrays and Pointers


char a[10]=“Hello”;
char *str = a;
printf(“%d %d %d\n”, sizeof(a), sizeof(str), strlen(a));
• Output:
10 4 5
§ Double Dimension arrays and double pointers
main()
{
char a[5][10]={"One", "Two", "Three", "Four", "Five" };
char **str = a;
A
char *b[5]={"One", "Two", "Three", "Four", "Five" }; L
char **str1 = b;
T I
E N
printf("%d %d %d %d\n", sizeof(a), sizeof(str), sizeof(b), sizeof(str1));
printf("%p %p %p %p %p %p\n", a, str, &a[1], &str[1], &a[1][1], &str[1][1]);
I D
printf("%p %p %p %p %p %p\n", b, str1, &b[1], &str1[1], &b[1][1], &str1[1][1]);
}
N F
• Output:
50 4 20 4 C O
O
0x22cca0 0x22cca0 0x22ccaa 0x22cca4 0x22ccab 0x1
R
P
0x22cc60 0x22cc60 0x22cc64 0x22cc64 0x403005 0x403005

WI
Wipro confidential 11
Pointers – Basics

§ Arrays and Pointers


char a[10]=“Hello”; a[1]: Second Str points to a
char *str = a; dimension size of a pointer.&str[1] is
printf(“%d %d %d\n”, sizeof(a), is 10 and hence 10 str+1 and since size
sizeof(str), strlen(a)); is added. of a pointer is 4
• Output: bytes, str + 1
10 4 5 translates to
§ Double Dimension arrays and double pointers 0x22cca0 + 4
main()
{
char a[5][10]={"One", "Two", "Three", "Four", "Five" }; Add 1 to a[1]
20: because
char **str = a;
A L
it is array of
char *b[5]={"One", "Two", "Three", "Four", "Five" };
char **str1 = b; T I
5 pointers
E N
printf("%d %d %d %d\n", sizeof(a), sizeof(str), sizeof(b), sizeof(str1));
D
printf("%p %p %p %p %p %p\n", a, str, &a[1], &str[1], &a[1][1], &str[1][1]);
I
N F
printf("%p %p %p %p %p %p\n", b, str1, &b[1], &str1[1],
&b[1][1], &str1[1][1]); &str[1][1] translate to
}
C O &(*(*(str+4) + 1)), i.e

• &(*(*(0x22cca4) + 1))).
Output:
50 4 20 4 R O This is equal to
P
WI
0x22cca0 0x22cca0 0x22ccaa 0x22cca4 0x22ccab 0x1 &(*(0 + 1)) and is equal
0x22cc60 0x22cc60 0x22cc64 0x22cc64 0x403005 0x403005 to 1 and str[1][1] will be
a junk value

Wipro confidential 12
Pointer Basics

&str1[0][0] b

&str[0][0]
0 1 2 3 4 5 6 7 8 9
a[0] O n e \0 b[0] One\0
a[1] T w o \0 b[1]L Two\0
a[2] T h r e e \0 I A Three\0
N T b[2]
a[3] F o u r \0
D E b[3] Four\0

FI b[4] Five\0
a[4] F i v e \0
O N
C
&str[1][1] translates to
&(*(*(str+4byte) + 1)), i.e
R O
P
WI
&(*(*(0x22cca4) + 1))).
This is equal to &(*(0 + str1[1][0]=
1)) and is equal to 1. So str1[1]=*(st str1[1][1]
str[1][1] will be a junk r1 + 4byte) *(*(str1+4bytes
value )+0) = T
Wipro confidential 13
Pointer Basics

a b
Junk\0

0 1 2 3 4 5 6 7 8 9
a[0] O n e \0 b[0] One\0

a[1] T w o \0 b[1]AL Two\0


T I
b[2] Three\0
a[2] T h r e e \0
EN
a[3] F o u r \0 I D b[3] Four\0

NF b[4] Five\0
a[4] F i v e \0
CO
char *temp = “junk”; R
O
IP
char *temp= “junk”;
a[0]=temp;
W b[2] = temp;

Wipro confidential 14
Pointers – Arithmetic & Casting

typedef struct
{
int day;
ef be ad de ee ff c0 00 ‘a’ ‘b’ ‘c’ ‘d’ ‘e’ 0 0 0 1f ca af de de ca 0 0 1 0 0 0
int month;
int year;
} Date;
all
cp+1 sp+1 ip+1cp+5 sp+3 ip+2 dp+1 dp+2
ip + 3 ip + 6
int abc=0xdeadbeef; sp + 8 sp + 16
int def=0xc0ffee;
char ghi[6]=“abcde”; cp + 12 cp + 24
int jkl = 0xdeafca1f;
short mno = 0xcade;
A L
I
• When a pointer is incremented by 1, depending upon
ofTbytes moved will defer.
Date pqr = { 1, 1, 2006 };
the type, number N
main()
{ D E
int *ip = &abc;
• When casting I from one type to another
Fcare alignment issues (SIGBUS)
short *sp = (short *)&abc;
char *cp = (char *) &abc; O
• TakeN
Date *dp = (Date *) &abc; C
……..
O • Keep in mind that number of bytes that will move
PR for every increment/decrement will change.
}

Note: Little endian architecture assumed


WI
Wipro confidential 15
Pointers – Function pointers

§ Pointers can point to functions as well in addition to variables.


• Declaration example: int (*f1)(int,char **) -> Pointer to a function that returns int and takes
one integer and one char double pointer as arguments.
• Assignment example: f1=main;
§ All the pointer arithmetic, casting, etc is applicable function pointers also.
void * fast_algo(int size);
void * mid_algo(int size);
void * slow_algo(int size);
typedef enum { HIGHSPEED_HIGHMEM, MIDSPEED_MIDMEM, LOWSPEED_LOWMEM } ALGO_CLASS;
ALGO_CLASS x;
void* (*MemAllocAlgo[3])(int) = { fast_algo, mid_algo, slow_algo};
void* (*MyAlloc)(int);
void AssignAllocator(ALGO_CLASS user_choice)
A L
{
T I
void* (**TempMyAlloc)(int); E N
TempMyAlloc = MemAllocAlgo;
I D
N F
C O
MyAlloc = MemAllocAlgo[user_choice];
/* Alternate1: MyAlloc= TempMyAlloc[user_choice]

}
R O
Alternate 2: MyAlloc = *(TempMyAlloc + user_choice) */

P
WI
Wipro confidential 16
Volatile pointers

§ Volatile keywords informs compiler that optimisations must be disabled for


that variable.
§ The following code has a problem. Compiler will not generate code for
disabling interrupt.

#define BASE_ADDRESS 0x80808000


#define INTERRUPT_REGISTER_OFFSET 0x10
CriticalSection()
{
int *intr_reg = (BASE_ADDRESS + INTERRUPT_REGISTER_OFFSET);
*(intr_reg) = 1; /* disables interrupt */
A L
I
/* critical code, interrupt must be disabled here */
T
…….
E N
…….
I D
/* critical code is executed, interrupt can be enabled here */
NF
*(intr_reg) = 0; /* enables interrupt */
}
C O
R O
§ The problem can be solved simply by defining intr_reg as volatile:
P
WI
volatile int *intr_reg = (BASE_ADDRESS + INTERRUPT_REGISTER_OFFSET);

Wipro confidential 17
Think about this – Volatile & Constant together

§ Can constant and volatile be used together during a


declaration?
§ Example:
• volatile int * const p = 0xc8000000;

A L
TI
E N
I D
NF
C O
R O
P
WI
Wipro confidential 18
Bit Manipulations

main()
{
int x = -10;
printf(“%d\n”, ~x+1);
}

main()
{
unsigned int x = 5; A L
while(--x >= 0) TI
{ E N
I D
printf(“Hello World\n”);
NF
}
C O
}
R O
P
WI
Wipro confidential 19
Bit Manipulations

main()
Output: 10
{
~x represents one’s compliment of x.
int x = -10;
~x+1 represents two’s compliment of x. (i.e
printf(“%d\n”, ~x+1); negative of x)
}

main()
{ HelloWorld is printed infinitely.
unsigned int x = 5; X becomes MAXINT A Lwhen it is decremented
while(--x >= 0) while it is havingT I a value of 0.
{ E N
I D
printf(“Hello World\n”);
N F
}
C O
}
R O
P
WI
Wipro confidential 20
Arithmetic and Logical Shifts

main()
Output: 0xC0000000
{ Signed number, “sign extension” happens
int x = 0x80000000; for right shift. (Arithmetic shift)
printf(“%x\n”, x >> 1);
}

main()
A L
{
T I
unsigned int x = 0x80000000; E N
printf(“%x\n”, x >> 1); I D
F 0x40000000
Output:
N
} O
Unsigned
C number, “sign extension”
doesn’t happen for right shift. (Logical shift)
R O
P
WI
Wipro confidential 21
Advanced Topics

§ Handy Bitwise Expressions


§ Stack frames à What happens during function calls
§ Variable arguments à How is it implemented?
§ Dynamic memory allocation à How can it be implemented?
§ Executable File contents

A L
TI
E N
I D
NF
C O
R O
P
WI
Wipro confidential 22
Handy Bitwise Expressions

Expression Purpose Remarks


1 X&1 Check whether number All numbers are interms of 0’s and 1’s and
is odd or even hence it is sufficient check the last bit
2 X << 1 Multiply by 2

3 X >> 1 Divide by 2

4 ~X+1 Negative the number Negative numbers are represented by two


complement. (one’s complement +1)
5 X ^ all’ones Bit toggling (equivalent
to ~)
6 X >> 31 To find out the sign of
A L is 0 or -1 based on the sign.
Result
the number of X
T I
7 Mask = X >> 31
comparisions E N
ABS(X) without using Mask contains all zeros if X is positive and
all ones if X is negative.
Result = (~Mask & X) | (Mask & (-X))

I D
F
8 Mask = (X-Y) >> 31 Min(X, Y) without using Mask contains all zeros if Y is less than or
Result = (Mask & X) | (~Mask & Y)
O N
comparisions equal to X and all ones if X is less than Y.

9 Mask = (X-Y) >> 31


C
Max(X, Y) without using
comparisions
Mask contains all zeros if X is greater than
or equal to Y and all ones if Y is greater

RO
Result = (Mask & Y) | (~Mask & X)
than X.

I P
W
Wipro confidential 23
Exercise 1: Power of 2.

§ Come up with an “handy” expression that can be used to


detect whether the given number is a power of 2.
§ Clue: All number that is a power of 2 will have just one bit set.
• Examples:
• 1 – 00000001
• 2 – 00000010
• 4 – 00000100
A L
• 8 – 00001000
TI
• 16- 00010000
E N
• 32 -00100000
I D
NF
C O
R O
P
WI
Wipro confidential 24
X86 Stack view during function calls in C

Sample program:
/* assuming EBP as a integer pointer */ ESP
int f2(int x1, int y1) /* x1 is *(EBP+2), y1 *(EBP + 3) */
{ Saved regs in f2
int l5 = 110; /* l5 is *(EBP – 1), l6 is *(EBP -2) */ l6
int l6 = 120; l5
Lower EBP
Memory Prev Frame Ptr
return (0)
Ret addr in f1
} x1
y1

int f1(int x, int y) Stack grows Saved regs in f1

AL
{ l4
int l3 = 50; this way
int l4 = 60;
T I l3
Prev Frame Ptr
return f2(l3 + x, l4 + y);
/* right most argument pushed to stack first */
E N Ret addr in main

I D x

NF
} Higher y
main()

CO
Memory Saved regs in main
{
int l1 = 10; l3
int l2 = 20;
int l3 = f1(l1 + 20, l2 + 20);
R O l2

P l1

WI
}
Prev Frame Ptr

Wipro confidential 25
Scope – Check your understanding now

§ Is scope of global and static variables clear?


§ Following code is sequence is perfectly legal. How is it handled?
f1(int x, int y)
{
int abc = 0xdeadbeef;

printf(“%x\n”, abc);
A L
TI
{
E N
int abc = 0xc0ffee;
I D
int x = 0x100;
NF
printf(“%x\, %xn”, abc, x);
C O
}
} R O
P
WI
(Clue: Local variables can get into stack or register)

Wipro confidential 26
Function Arguments – Check your understanding
now

§ A new function named “File1Func1” is implemented in file1


§ Prototype of the function is as follows
• Int File1Func1();
§ In file1, the function is implemented as follows:
Int
File1Func1(int x, int y)
{
…..
A L
}
TI
E N
D
§ In file2, this function is called as follows.
I
File1Func1(10,20,30);
N F
O
§ File1Func1 is called with 3Carguments, while the
O
implementation takes only two arguments. What will happen
now? PR
WI
Wipro confidential 27
Exercise 2: Stack tracing

§ You have a.o file and have a.h and b.h


§ a.h contents are:
• extern int func1(int x, int y);
• extern int func2(int x, int y);
§ b.h contents are
• extern int func3(int x, int y);
§ Given that calling sequence is: A L
TI
• Main->func1->func2->func3
E N
ID function func3
§ You got to implement b.c that has
• func3 should print value ofNxFpassed to func1.
CO
R O
P
WI
Wipro confidential 28
Security issue – Buffer Overflow on stack

main(int argc, char *argv[])


{
int flag;
char filename[16];

if (argc != 2)
{
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(1);
}
….
flag = check_permission();

........
A L
strcpy(filename, argv[1]); /* Depending upon argv[1], the return address could get corrupted */

if (flag == 0xdeadbeef)
T I
{
E N
/* execute the as root or deposit million dollars in a bank account */
}
I D
else
{
NF
} C O
/* execute the program as normal user, deduct $10 from an account */.

}
R O
P
WI
/* clever hacker will manage the argv[1] such that return address is changed to a desired location. Or he can change the value of flag
*/
/* typically entire binary program of “undesired program” is also passed as an argument, along with return address change */

Wipro confidential 29
Variable arguments in C

§ va_start(ap, num_args) à Typically implemented as macro, just


initializes ap such that it points to first un-named argument. (It
will use frame pointer + offset of second argument from fp to
iniatialize ap)
§ va_arg(ap, type) à Returns an argument & updates ap
§ va_end(ap) à Implementation specific cleanups.

§ Number of arguments should be known directly or indirectly


• A L number of arguments
main: argc is the first argument that will tell
• T I found from number of %
Printf: number of arguments are indirectly
in format argument EN
IDknown
§ Type of the arguments should be
F
• main: Strings (char *argv[]) N

O
printf: character followingC% tells the argument type
R O
P
WI
Wipro confidential 30
Exercise 3: MyPrintf Implementation

§ Implement myprintf(char *fmt, …) function


§ Handle %d, %x, %c and %s types in fmt string.
§ You can use putchar function to output a character on to the
screen.
§ If you use any other C library function, you must implement
them as well.
A L
TI
E N
I D
NF
C O
R O
P
WI
Wipro confidential 31
Dynamic Memory allocation -- Internals

§ Dynamic memory allocation


• Memory allocated from heap
§ In unix,
• heap typically comes after BSS area
• Brk call is used to change the “data segment” memory allocated to
a process
§ Each memory allocation needs additional overhead memory
that is also taken from heap.
§ Typical implementation, each allocation preceded by MCB
(Memory control Blocks)
A L
§ MCB structure I T
struct MCB
E N
{
I D
int is_available;
NF
};
int size;
C O
R O
§ Many approaches are
I P there. Serious research topic.
W Requested vs Allocated, Number of chunks
• Space efficiency:
• Speed: How quickly malloc/free can be executed. Critical in RTOS.
Wipro confidential 32
Dynamic Memory Allocation

Main()
Heap Start {
ptr1
MCB 1: 0, 108 char *ptr1 = malloc(100);
Allocation 1 char *ptr2 = malloc(200);
MCB 2: 0, 208 ptr2 Control
Last allocation Allocation 2
…….
Free Memory free(ptr1);
….
ptr1 = malloc(300);
A L ….
Heap End

T I
E N free(ptr1)

ID
….
Note:

N
When 100 bytes are requested, actually 100 bytes
F
+
ptr1 = malloc(50);

CO
sizeof(MCB) has been utilized. MCB is the overhead. ….

R O
I P free(ptr1);

W free(ptr2);
}
Wipro confidential 33
Dynamic Memory Allocation

Main()
Heap Start {
MCB 1: 1, 108 char *ptr1 = malloc(100);
Allocation 1 char *ptr2 = malloc(200);
MCB 2: 0, 208 ptr2

Allocation 2
…….
MCB 3: 0, 308 free(ptr1);
ptr1
Last allocation Allocation 3
….
Free Memory
ptr1 = malloc(300);
A
Control L ….
Heap End

T I
E N free(ptr1)

ID
….
Note:

NF
ptr1 = malloc(50);
free doesn’t take size as the the argument. It is
calculated by accessing *(ptr1 – sizeof(MCB) +
sizeof(int))
CO ….

R O
P
MCB1 & allocation 1 remains intact even though it is free(ptr1);

WI
not allotted.
free(ptr2);
}
Wipro confidential 34
Dynamic Memory Allocation

Main()
Heap Start {
ptr1
MCB 1: 0, 108 char *ptr1 = malloc(100);
Allocation 1 char *ptr2 = malloc(200);
MCB 2: 0, 208 ptr2

Allocation 2
…….
MCB 3: 1, 308 free(ptr1);
Last allocation
Allocation 3
….
Free Memory
ptr1 = malloc(300);
A L ….
Heap End

T I
E N free(ptr1)

ID
….
Note:

N
First allocation is re-utilised. That is 100 bytes are
F ptr1 = malloc(50);

allocated, when 50 bytes are requested.


CO Control ….

R O
I P free(ptr1);

W free(ptr2);
}
Wipro confidential 35
Dynamic Memory Allocation

Main()
Heap Start {
MCB 1: 1, 108 char *ptr1 = malloc(100);
Allocation 1 char *ptr2 = malloc(200);
MCB 2: 1, 208
Allocation 2
…….
Last allocation MCB 3: 1, 308 free(ptr1);
Allocation 3
….
Free Memory
ptr1 = malloc(300);
A L ….
Heap End

T I
E N free(ptr1)

ID
….

NF
ptr1 = malloc(50);

CO ….

R O
P free(ptr1);

WI Control free(ptr2);
}
Wipro confidential 36
Pros & cons of MCB approach

§ Simple and Very fast


§ MCB overhead per allocation
§ Allocation based on first match, rather than best match. (100
bytes allocated, instead of 50 bytes)
• ptr1=malloc(1024 * 1024); free(ptr1), ptr1=malloc(10); we would
allocate 1MB for 10 bytes.
• Improvements: free space could divided into chunks of fixed size.
ALthe wastage.
(typically in power of 2). This would limit
Iexcess bytes to
§ In case of alignment issues, attach the
N T
previous MCB.
D E
F I
§ Doesn’t create new chunks, unless all previous allocated
ON
chunks are used. Less fragmentation.
C
R O
P
WI
Wipro confidential 37
Rainy day scenarios – What happens now?

1. Lost memory
ptr1=malloc(100);
ptr1=malloc(200);
2. Double free
ptr1=malloc(100);
free(ptr1);
free(ptr1);
3. Accessing memory after free
A L
ptr1=malloc(10); TI
free(ptr1) E N
*(ptr1+9) = ‘\0’’; I D
NF
4. Out of range access
C O
ptr1=malloc(10);
*(ptr1+10) = ‘\0’;
P RO
W I
Wipro confidential 38
Exercise 4: Implement myalloc & myfree functions

§ Requirements:
• You should not use any of the existing C or C++ library calls for
memory alloc (malloc, calloc, realloc, new, etc…)
• Implement void *myalloc(int elem_size) and void free(void *p);
• You also have to implement void InitMem(char *ptr, int
size_in_bytes)
• Through this interface, one big chunk of memory will be provided to
you.
L
• Use the part of these memory in further calls of myalloc & myfree
A
functions.
T I
• N
You also have to implement int MemEfficiency()
E
that returns
D
number of MCBs (chunks) present.
• FI following aspects
If you are adventurous, address
N

C O
Minimize the fragmentation by joining adjacent free blocks

O
Put a time limit towards myalloc and myfree functions.
R

P
Make it thread safe. J
• WI
Allocated memory should align with the size requested. Example:
myalloc(10) means the pointer returned must be divisible by 10.

Wipro confidential 39
Security issue – buffer overflow on heap

main(int argc, char *argv[])


{

char *filename_p;

if (argc != 2)
{
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(1); A L
}
T I
filename_p = malloc(1024);
E N
I D
N F
get corrupted */ C O
strcpy(filename, argv[1]); /* Depending upon argv[1], MCBs or even other areas can

R O
P
WI
....
}

Wipro confidential 40
Security issues – Be aware

§ We need to write defensive program to escape security attacks


• Know length of a string before you copy.
• A defence mechanism needed before using any size related
information coming across network.
• Beware of DOS attacks.
• If you write a server program, beware not to accept too many
connections from same client in a short period.
A L
TI
E N
I D
NF
C O
R O
P
WI
Wipro confidential 41
Phases & components of a program compilation &
execution

S.N Component Phase Remarks


o
1 Preprocessor Pre-processing Expands macros
2 Compiler Lexical analysis, Creates *.o files
Syntax/Semantic analysis,
Code generation, Code
optimisation
3 Linker Resolve unknown symbols Creates executable files
4 Loader Dynamic Linking Loader loads the executable to
L
memory.
A
T I
Dynamic linking: Resolves symbols
from shared libraries
5 Loader Relocation N
E Changes absolute reference of a
I D symbol to correct virtual address

N F
C O
O
Note: Nowadays, linking typically refers to static linking. Loader is
R Relocation, etc.
P
taking care of dynamic linking,
I
W
Wipro confidential 42
Where the data goes?

S.No Type of Data Sections


1 Local variables (automatic variable) Stack, not part of
executable file
2 Dynamically allocated memroy Heap, not part of
executable file
3 Code (functions) .text
4 Global variables – Initialized .data
A L
5 Global variables – Initialized and const
I .rodata
Tin .rodata
6 Const Strings (example: “%d” used
E N
format string of printf)
I D
7 N F
Global variable – Not initialized .bss, only size info
C O kept in executable file
8 Which symbols to R O
relocated .relaxxx
P
Which symbolsIto resolved dynamically .dynsym
9
W
Wipro confidential 43
Example code

• Let us do elfdump/readelf on the executable created using following program.


File 1: test.c
#include <stdio.h> File 2: test1.c
int my_global = 1; static
int my_uninit_data[100]; void local_f1()
char my_string[]="Hello World"; {
char *my_str_p = “Hello Wipro”; static int my_static = 4;
extern void f2(); printf("%d", my_static);
static }
void local_f1()
{
A L
static int my_static = 3;
void f2()

T I
printf("%s %d\n", my_str_p, my_static); N
{

E local_f1();
my_uninit_data[99] = 0xdeadbeef;
I D}
f2();
N F
}
C O
main()
R O
{
I P
static int my_static = 3;
W
printf("%d %s %d\n", my_global, my_string, my_static);
local_f1(); }
Wipro confidential 44
Output of elfdump or readelf

Symbol table '.symtab' contains 119 entries:


Num: Value Size Type Bind Name
83: 00000000 0 FILE LOCAL test1.c
84: 080494ac 4 OBJECT LOCAL my_static.0
85: 08048328 51 FUNC LOCAL local_f1
86: 080494b0 4 OBJECT LOCAL my_static.1
87: 00000000 0 FILE LOCAL test.c
88: 080494b4 4 OBJECT LOCAL my_static.0
89: 08048390 30 FUNC LOCAL local_f1
93: 080494a8 4 OBJECT GLOBAL my_str_p
97: 0804949c 12 OBJECT GLOBAL my_string
98: 080483ae 13 FUNC
103: 0804835b 53 FUNC
GLOBAL f2
GLOBAL main A L
109: 080495e0 400 OBJECT GLOBAL my_uninit_data
TI
117: 08049498 4 OBJECT GLOBAL my_global
E N
Section Headers: I D
[Nr] Name Type Addr
N F
Size
[12] .text PROGBITS 08048278 O 0001cc
[14] .rodata PROGBITS 08048460 C 000028
[16] .data PROGBITS O
0804948c
R
00002c
[22] .bss NOBITS
P
080495c0 0001b0

WI
Wipro confidential 45
Exercise 5: Disassemble the code

§ Compile the test.c and test1.c with –S option.


§ This will generate test.s and test1.s files
§ Open these files and try to locate the sections in which various
variables used in test.c/test1.c are present.

A L
TI
E N
I D
NF
C O
R O
P
WI
Wipro confidential 46
Thank you.

A L
T I
E N
I D
N F
C O
R O
P
WI
Information contained and transmitted by this presentation is proprietary to Wipro Limited and is intended for use only by the individual or entity to which it is addressed,
and contains information that is privileged, confidential or exempt from disclosure under applicable law.

Wipro confidential 47

You might also like