diff --git a/info0939/README.md b/info0939/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..623b3675d9a0e5a2cc66da8246f68b263ec15bb1
--- /dev/null
+++ b/info0939/README.md
@@ -0,0 +1,55 @@
+Prerequisites for the class:
+---
+ * Having access to a Unix machine
+ * Having access to the compiler (`gcc` or `clang`), the debugger (`gdb`) and `wget`
+ * NIC5 satisfies all the requirements
+
+Instructions for downloading the example code
+---
+The git repository is located at [here](https://gitlab.onelab.info/mcicuttin/snippets/INFO0939) (`https://gitlab.onelab.info/mcicuttin/snippets/INFO0939`). We will use the following files:  
+- `intdiv.c` for the `assert()` example on the integer division program  
+- `stack_corrupt.c` for a debugging exercise  
+- `cache.c` for a profiling exercise  
+
+You can download the files on your machine or on NIC5 via `wget`:
+
+```
+# This command is needed only when you open a new shell
+export REPO_BASE=https://gitlab.onelab.info/mcicuttin/snippets/INFO0939/-/raw/master/
+
+# Files are then donwloaded as following:
+wget $REPO_BASE/intdiv.c
+wget $REPO_BASE/stack_corrupt.c
+wget $REPO_BASE/cache.c
+```
+
+GDB Cheatsheet
+---
+To debug with GDB: `gdb <progname>`, then  
+
+* `r`: Run the program  
+* `bt`: Print the backtrace of a crashed program  
+* `frame`: Select the stack frame you want to analyze  
+* `s` or `step`: step one statement, enter the function if statement is a function call   
+* `n` or `next`: execute next statement
+* `c`: continue until the end of the program or the next breakpoint
+* `break <file:line>`: set a breakpoint
+* `p`: print the value of a variable
+
+Integer division program & `assert()`
+---
+You are not really required to run this code, but...  
+
+* Compile with `gcc -g -o intdiv intdiv.c` (debug mode)  
+* Compile with `gcc -O3 -DNDEBUG -o intdiv intdiv.c` (release mode)  
+* Try to pass a negative integer to the function, compile the program in both modes and see what happens
+
+Debugging exercise with `stack_corrupt.c`
+---
+
+* Compile with `gcc -g -o stack_corrupt stack_corrupt.c`
+* Run with `./stack_corrupt`. What do you see?
+* Launch the code in GDB and try to explain what you see
+
+Profiling exercise with `cache.c`
+---
diff --git a/info0939/cache.c b/info0939/cache.c
new file mode 100644
index 0000000000000000000000000000000000000000..2a5f7ffa9d7be301924531d7c843192c9cd1da3f
--- /dev/null
+++ b/info0939/cache.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+static void *
+Malloc(size_t size)
+{
+    void *ret = malloc(size);
+    if (!ret)
+    {
+        printf("malloc() failed\n");
+        abort();
+    }
+    return ret;
+}
+
+static void
+preheat(double *out, const double *mat, const double *vec,
+    size_t m, size_t n)
+{
+    for (size_t i = 0; i < m; i++)
+        for (size_t j = 0; j < n; j++)
+            out[i] += mat[i*n + j] * vec[j];
+}
+
+static void
+mvp_good(double *out, const double *mat, const double *vec,
+    size_t m, size_t n)
+{
+    for (size_t i = 0; i < m; i++)
+        for (size_t j = 0; j < n; j++)
+            out[i] += mat[i*n + j] * vec[j];
+}
+
+static void
+mvp_bad(double *out, const double *mat, const double *vec,
+    size_t m, size_t n)
+{
+    for (size_t j = 0; j < n; j++)
+        for (size_t i = 0; i < m; i++)
+            out[i] += mat[i*n + j] * vec[j];
+}
+
+static double
+compute_time(const struct rusage *rstart, const struct rusage *rend)
+{
+    double ret = rend->ru_utime.tv_sec + rend->ru_utime.tv_usec/1e6;
+    ret -= rstart->ru_utime.tv_sec + rstart->ru_utime.tv_usec/1e6;
+    return ret;
+}
+
+int
+main(int argc, char * const argv[])
+{
+    int rows = 0, cols = 0;
+    int ch;
+
+    while ( (ch = getopt(argc, argv, "r:c:")) != -1 )
+    {
+        switch (ch)
+        {
+            case 'r':
+                rows = atoi(optarg);
+                break;
+
+            case 'c':
+                cols = atoi(optarg);
+                break;
+
+            case '?':
+            default:
+                printf("Usage: %s -r <rows> -c <cols>\n", argv[0]);
+                exit(EXIT_FAILURE);
+        }
+    }
+
+    if (rows < 1 || cols < 1)
+    {
+        printf("Number of rows and cols must be >1\n");
+        exit(EXIT_FAILURE);
+    }
+
+    double *mat = (double *) Malloc(rows*cols*sizeof(double));
+    double *vec = (double *) Malloc(cols*sizeof(double));
+    double *out = (double *) Malloc(rows*sizeof(double));
+
+    preheat(out, mat, vec, rows, cols);
+
+    struct rusage rstart, rend;
+    getrusage(RUSAGE_SELF, &rstart);
+    mvp_good(out, mat, vec, rows, cols);
+    getrusage(RUSAGE_SELF, &rend);
+
+    double time = compute_time(&rstart, &rend);
+    printf("Good MVP: %g secs\n", time);
+
+    getrusage(RUSAGE_SELF, &rstart);
+    mvp_bad(out, mat, vec, rows, cols);
+    getrusage(RUSAGE_SELF, &rend);
+
+    time = compute_time(&rstart, &rend);
+    printf("Bad MVP: %g secs\n", time);
+
+    free(out);
+    free(vec);
+    free(mat);
+    return 0;
+}
+
diff --git a/info0939/intdiv.c b/info0939/intdiv.c
new file mode 100644
index 0000000000000000000000000000000000000000..19c965ec47d96113aa20822df61bb4a1a1b1a364
--- /dev/null
+++ b/info0939/intdiv.c
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <assert.h>
+
+typedef struct div_result {
+    int quo;
+    int rem;
+} div_result_t;
+
+static void
+integer_division(int x, int y, struct div_result *res)
+{
+    /* Precondition: for the program to work, the input must satisfy
+     * x >= 0 (just to keep things simple) 
+     * y > 0 (because division by zero is not defined)
+     */
+    assert(x >= 0 && y > 0);
+
+    res->quo = 0;
+    res->rem = x;
+
+    /* The loop invariant is that
+     * - quotient * y + res has to be equal to x
+     * - y > 0
+     * The invariant must be true before, during and after the loop.
+     */
+    assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 );
+    
+    while (res.rem >= y)
+    {
+        /* At this point invariant AND while condition should be valid */
+        assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 && res.rem >= y );
+
+        res.rem = res.rem - y;
+        res.quo = res.quo + 1;
+
+        /* At this point the invariant should be re-established */
+        assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 );
+    }
+
+    /* Postcondition: invariant AND NOT while condition */
+    assert( (res.quo*y + res.rem == x) && res.rem >= 0 && y > 0 && rem < y );
+
+    /* In addition, note that IF we enter the cycle THEN res.rem ALWAYS
+     * decreases. res.rem is a ``bound function'' and allows you to say
+     * that your program ALWAYS terminates. */
+}
diff --git a/info0939/stack_corrupt.c b/info0939/stack_corrupt.c
new file mode 100644
index 0000000000000000000000000000000000000000..76b07ea222fde87bcfd8a6af16ae942819dec65d
--- /dev/null
+++ b/info0939/stack_corrupt.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFSZ   4
+
+struct mystruct
+{
+    int     x;
+    char    y[BUFSZ];
+};
+
+static void
+fun(struct mystruct *s)
+{
+    s->x = 42;
+    strcpy(s->y, "Hello world, this is INFO0939");
+}
+
+int main(void)
+{
+    int *x = (int *) malloc(400);
+    struct mystruct s;
+    fun(&s);
+    free(x);
+    return 0;
+}