5c. De stack

2021-02-19
slides.com/jod/pt_5c

Docent: Jo Devriendt

Assistent: Ann Philips

Coördinator: Joost Vennekens

voornaam.achternaam@kuleuven.be

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Simpel geheugenlayout van een proces

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

  • Geheugen bevat data en instructies
  • Dynamisch geheugen is geheugen dat krimpt en groeit, naargelang de vraag van het programma. Opgedeeld volgens
    • de stack (rest van de presentatie)
    • de heap (hst 8)
lagere adressen
hogere adressen

instructies in de executable

heap

 

...
 


stack

statische data

command line argumenten

Simpel geheugenlayout van een proces

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

  • Merk op: instructies zitten in geheugen en hebben adres
  • programmateller / instructiepointer houdt bij wat adres is van volgende instructie
lagere adressen
hogere adressen

instructies in de executable

heap

 

...
 


stack

statische data

command line argumenten

De stack

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

  • Genoemd naar datatype uit hst 9.4
  • Twee operaties:
    • push (zet erop)
    • pop (haal eraf)

De stack

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

element 1

element 2

element 3

element 4

element 5

frame 4

frame 4

frame 4

  • Genoemd naar datatype uit hst 9.4
  • Twee operaties:
    • push (zet erop)
    • pop (haal eraf)

De stack

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

element 1

element 2

element 5

element 4

  • Genoemd naar datatype uit hst 9.4
  • Twee operaties:
    • push (zet erop)
    • pop (haal eraf)

De stack

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

lagere adressen
hogere adressen

instructies in de executable

heap

 

...
 


stack

statische data

command line argumenten

  • Stack houdt data bij tijdens het oproepen van procedures
    • ook call stack genoemd
  • 1 frame per procedure-oproep:
    • terugkeeradres: naar welke instructie moet teruggekeerd worden op het einde van de procedure
    • waardes van lokale variabelen
    • waardes van argumenten van procedure
  • procedure start → frame push
  • procedure eindigt → frame pop

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}
HIER KOMT
DE STACK

De stack:
voorbeeld

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 1: main na regel 20

frame
main
terugkeeradres
0
3
2
1
.
i
a[2]
a[1]
a[0]

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 2: maxEerst na regel 12

frame
main
terugkeeradres
0
3
2
1
.
i
a[2]
a[1]
a[0]
frame maxEeerst
3
&
terugkeeradres
1
n
b
a[2]
j

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 3: swap na regel 5

frame
main
terugkeeradres
0
3
2
1
.
i
a[2]
a[1]
a[0]
frame maxEeerst
terugkeeradres
1
a[2]
j
frame
swap
&
&
terugkeeradres
1
y
x
a[2]
tmp
3
&
n
b

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 4: einde van swap

frame
main
terugkeeradres
0
3
1
2
.
i
a[2]
a[1]
a[0]
frame maxEeerst
terugkeeradres
1
a[2]
j
frame
swap
&
&
terugkeeradres
1
y
x
a[2]
tmp
3
&
n
b

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 5: maxEerst na regel 13

frame
main
terugkeeradres
0
3
1
2
.
i
a[2]
a[1]
a[0]
frame maxEeerst
3
&
terugkeeradres
1
n
b
a[2]
j

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 6: opnieuw swap na regel 5

frame
main
terugkeeradres
0
3
1
2
.
i
a[2]
a[1]
a[0]
frame maxEeerst
3
&
terugkeeradres
2
n
b
a[2]
j
frame
swap
&
&
terugkeeradres
2
y
x
a[2]
tmp

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}
frame
main
terugkeeradres
0
2
1
3
.
i
a[2]
a[1]
a[0]
frame maxEeerst
3
&
terugkeeradres
2
n
b
a[2]
j

Situatie 7: opnieuw maxEerst na regel 13

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 8: einde maxEerst

frame
main
terugkeeradres
0
2
1
3
.
i
a[2]
a[1]
a[0]
frame maxEeerst
3
&
terugkeeradres
3
n
b
a[2]
j

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 9: einde van regel 21

frame
main
terugkeeradres
0
2
1
3
.
i
a[2]
a[1]
a[0]

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#include <stdio.h>
#define N 3

void swap(int* x, int* y){
  int tmp = *x;
  *x = *y;
  *y = tmp;
}

void maxEerst(int* b,int n){
  for(int j=1; j<n; ++j){
    if(b[j]>b[0]){
      swap(&b[0], &b[j]);
    }
  }
}

void main() {
  int a[N] = {1,2,3};
  for(int i=0; i<N; ++i){
    maxEerst(&a[i], N-i);
    printf("%d ",a[i]);
  }
}

Situatie 10: einde van main

frame
main
terugkeeradres
3
1
2
3
.
i
a[2]
a[1]
a[0]

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Versimpeld voorbeeld 5.6

$ ./a.out 2
m=2
a[2]=4
*** stack smashing 
detected ***: 
terminated
fish: “./a.out 2” 
terminated by signal 
SIGABRT (Abort)
#include <stdio.h>
#include <stdlib.h>
#define N 2

void func(int a[], int x) {
  for (int i=0; i<=x; ++i){
    a[i]=i*x;
  }
}

void main(int argc, char* argv[]) {
  int a[N];
  int m = atoi(argv[1]);
  
  printf("m=%d\n", m);
  func(a,m);
  printf("a[%d]=%d\n", m, a[m]);
}
$ ./a.out 1
$ ./a.out 1
m=1
a[1]=1

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Versimpeld voorbeeld 5.6

na lijn 13

main
.
NULL
&
&
2
terugadres
argv[1]
argv[0]
argv[2]
argc
m
2
m
?
a[1]
?
a[0]
$ ./a.out 2
#include <stdio.h>
#include <stdlib.h>
#define N 2

void func(int a[], int x) {
  for (int i=0; i<=x; ++i){
    a[i]=i*x;
  }
}

void main(int argc, char* argv[]) {
  int a[N];
  int m = atoi(argv[1]);
  
  printf("m=%d\n", m);
  func(a,m);
  printf("a[%d]=%d\n", m, a[m]);
}

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Versimpeld voorbeeld 5.6

na eerste keer lijn 7

func
.
2
&
terugadres
0
a
argv[0]
x
i
#include <stdio.h>
#include <stdlib.h>
#define N 2

void func(int a[], int x) {
  for (int i=0; i<=x; ++i){
    a[i]=i*x;
  }
}

void main(int argc, char* argv[]) {
  int a[N];
  int m = atoi(argv[1]);
  
  printf("m=%d\n", m);
  func(a,m);
  printf("a[%d]=%d\n", m, a[m]);
}
main
.
NULL
&
&
2
terugadres
argv[1]
argv[0]
argv[2]
argc
m
2
m
?
a[1]
0
a[0]
$ ./a.out 2

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Versimpeld voorbeeld 5.6

na tweede keer lijn 7

#include <stdio.h>
#include <stdlib.h>
#define N 2

void func(int a[], int x) {
  for (int i=0; i<=x; ++i){
    a[i]=i*x;
  }
}

void main(int argc, char* argv[]) {
  int a[N];
  int m = atoi(argv[1]);
  
  printf("m=%d\n", m);
  func(a,m);
  printf("a[%d]=%d\n", m, a[m]);
}
func
.
2
&
terugadres
1
a
argv[0]
x
i
main
.
NULL
&
&
2
terugadres
argv[1]
argv[0]
argv[2]
argc
m
2
m
2
a[1]
0
a[0]
$ ./a.out 2

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Versimpeld voorbeeld 5.6

na derde keer lijn 7

Incorrecte schrijfoperatie!

#include <stdio.h>
#include <stdlib.h>
#define N 2

void func(int a[], int x) {
  for (int i=0; i<=x; ++i){
    a[i]=i*x;
  }
}

void main(int argc, char* argv[]) {
  int a[N];
  int m = atoi(argv[1]);
  
  printf("m=%d\n", m);
  func(a,m);
  printf("a[%d]=%d\n", m, a[m]);
}
func
.
2
&
terugadres
2
a
argv[0]
x
i
main
.
NULL
&
&
2
terugadres
argv[1]
argv[0]
argv[2]
argc
m
4
m
2
a[1]
0
a[0]
$ ./a.out 2

Stack smash

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

  • Incorrect overschrijven van stackgeheugen buiten huidige frame
  • Ook stack overflow / stack underflow genoemd
  • Vorm van hacking: buffer overflow attack
$ ./a.out 2
m=2
a[2]=4
*** stack smashing detected ***: terminated 
fish: “./a.out 2” terminated by signal SIGABRT (Abort)

De stack tijdens debuggen

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Eenvoudige bug:
toekenning aan ongeïnitialiseerde pointer

void func2() {
  int* x;
  *x = 0;
}

void func1() {
  func2();
}

void main() {
  func1();
}
$ ./a.out
“./a.out” terminated by signal SIGSEGV 
(Address boundary error)

De stack tijdens debuggen

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

void func2() {
  int* x;
  *x = 0;
}

void func1() {
  func2();
}

void main() {
  func1();
}
$ gdb a.out -ex run -ex bt
...
Program received signal SIGSEGV, 
Segmentation fault.
0x0000555555555135 in func2 ()
#0  0x0000555555555135 in func2 ()
#1  0x0000555555555150 in func1 ()
#2  0x0000555555555165 in main ()

Stack trace: call stack frames op het moment dat de bug zich voordeed

Eenvoudige bug:
toekenning aan ongeïnitialiseerde pointer

Samenvatting

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

  • Deel van de data van een programma zit in de (call) stack
  • Frame per procedure-oproep
  • Frames bevatten argumenten, lokale variabelen, terugkeeradres
  • Stack smash / overflow / underflow: incorrect stackgeheugen overschrijven
  • Stack trace: samenvatting van frames op de stack, handig voor debuggen
Made with Slides.com