⚠️ Warning: This is not the current iteration of the course! Look here for the current offering.

Midterm Quiz (Fall 2025) #


1. Memory Organization (12 points) #

Ethan and Johnny are working on a program that will “swap” two strings by changing their pointers.  They write the following program:

void swap_strings(char* a, char* b) {
    char* temp = a;
    a = b;
    b = temp;
}

int main() {
    char* s1 = (char*)malloc(4);
    char* s2 = (char*)malloc(4);
    strcpy(s1, "cat");
    strcpy(s2, "dog");

    char* strs[] = {s1, s2};

    swap_strings(strs[0], strs[1]);
    printf("%s %s\n", strs[0], strs[1]);

    return 0;
}

QUESTION 1A How many bytes does the array strs occupy in memory?

QUESTION 1B After running this code, the print statement still prints “cat dog” instead of the intended (swapped) “dog cat”. Explain why. Your answer should be a few words, at most one sentence.

QUESTION 1C How could swap_strings be changed in order to fix the problem? Explain what should be changed, or provide a fixed version.

QUESTION 1D Johnny and Ethan give up on swapping strings and remove the call to swap_strings from the program. Instead, they decide to try something else: knowing that array elements are stored contiguously in memory, they suggest that it’s possible to print both strings together (i.e., “cat dog”) by changing the first string to remove the null-terminator, like this:

    s1[3] = ' ';             // Replace null terminator with a space
    printf("%s\n", strs[0]); // print both strings ("cat dog")?

Will this plan work? Explain why or why not. Answer “yes” or “no”, and then explain your reasoning in a few words, or at most one sentence.

2. Alignment (12 points) #

Karina and Curtis are organizing a Halloween costume contest! In order to track information about contestants and their costumes, they each decided to create a struct for the contest participants.

struct costume_info {
    char name[17]; // 16 chars + null terminator
    short contestantNum;
    int score;
    long costume;
    int* studentId;
};

QUESTION 2A What is the size of the costume_info struct? To express your answer, copy the struct definition above and add comments to indicate 1) how many bytes are allocated for each member of the struct and 2) how many bytes of padding (if any) are between each member.

QUESTION 2B Karina suggests changing the studentId member to store the student’s ID number directly (as a type int) instead of using a pointer. Does this change the size of the struct? Write “yes” or “no” and explain your reasoning (a few words, or roughly one sentence).

3. Assembly (11 points) #

Preparing for his midterms, Ignas decides to hack into the SciLi’s vending machines and finds the following assembly code. Ignas knows that the function takes in an integer representing the number of coins paid by the user, and returns an integer indicating the number of snacks to dispense, i.e., the function has the signature:

            unsigned int count_snacks(unsigned int coins);

Ignas also knows that the function contains a loop, and that all snacks cost the same amount. Here’s the code:

 1 count_snacks:
 2         movl    %edi, -20(%rsp)
 3         movl    $0, -4(%rsp)
 4         movl    $2, -8(%rsp)
 5         jmp     .L2
 6 .L4:
 7         cmpl    $2, -20(%rsp)
 8         jbe     .L3
 9         addl    $1, -4(%rsp)
10 .L3:
11         movl    -8(%rsp), %edx
12         subl    %edx, -20(%rsp)
13 .L2:
14         cmpl    $0, -20(%rsp)
15         jne     .L4
16         movl    -4(%rsp), %eax
17         ret

QUESTION 3A What line(s) of the assembly code represents the loop condition?

QUESTION 3B Write an expression in C that could represent the loop condition (i.e., the part that could go inside the while(...) or for(...))

QUESTION 3C How many coins does a snack cost? Explain your reasoning (a few words, at most one sentence).

QUESTION 3D How could you make one change to the assembly to make it dispense all of the snacks in the machine? Your change may add, modify, or remove at most one instruction. (You don’t know how many total snacks the machine has, but you can assume it has a lot fewer than UINT_MAX (0xffffffff), the maximum value for type unsigned int.)

To give your answer, please give a line number in the original assembly and suggest the change that would go there. Then, briefly explain how the change would achieve your goal.

4. Undefined Behavior (12 points) #

Consider the following C program. For each point in the code marked “Point <N>”, consider whether executing that line causes undefined behavior.

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>

void greet_sharks(char** names, int* num_sharks) {
    for(int i = 0; i < *num_sharks; i++) {
        printf("Hello %s\n", names[i]);
    }
}

int main() {
    char* shark_names[3] = {"Huda", "Alex", "Nick"};
    int len = 3;

    greet_sharks(shark_names, &len); // <------------------ POINT 1

    char new_name[6] = {'S', 'h', 'a', 'r', 'k', 'y'};
    shark_names[2] = new_name;
    greet_sharks(shark_names, &len); // <------------------ POINT 2

    shark_names[1] = "d";
    greet_sharks(shark_names, &len); // <------------------ POINT 3

    char* new_name2 = (char*)malloc(4);
    shark_names[1] = new_name2;
    greet_sharks(shark_names, &len); // <------------------ POINT 4

    char* shark = "Rahel";
    greet_sharks(&shark, 0);         // <------------------ POINT 5

    char* new_name3 = new_name2; // <----------| POINT 6 (any of these lines)
    free(new_name2);             // <----------|
    free(new_name3);             // <----------|
}

QUESTION 4A For each marked line, indicate if it causes undefined behavior. If the line causes undefined behavior, briefly explain why (a few words is fine, at most one sentence). If the line does not cause undefined behavior, no explanation is required. If the undefined behavior in one line would normally cause a segfault, assume that the other parts of the program continue unaffected.

You should have an answer for each of the following points in the code.

  1. POINT 1
  2. POINT 2
  3. POINT 3
  4. POINT 4
  5. POINT 5
  6. POINT 6

5. DMalloc (8 points) #

Rahel and Ignas are implementing DMalloc.  Similar to our version of the project, their implementation adds an 8-byte “secret” value to the end of each allocation in order to detect wild writes. The secret value they use is the following sequence of bytes (in hex):

             {0xaa, 0xbb, 0xcc, 0xdd, 0xaa, 0xbb, 0xcc, 0xdd}

To test out their implementation, they write the following program to create three 64-byte allocations on the heap:

int main() {
    char* a = dmalloc(64);
    char* b = dmalloc(64);
    char* c = dmalloc(64);

    // *** [ CODE HERE ] ***

    dfree(a);
    dfree(b);
    dfree(c);
}

… which allocates three regions of memory with addresses as shown in the diagram:

QUESTION 5A To test their implementation, Rahel and Ignas write some code that modifies memory, which they add to the program in the region labeled [ CODE HERE ].

For each line of code below, indicate if the change it makes would be detected by Rahel and Ignas’ implementation. To give your answer for each line, write “yes” or “no”, and include a brief explanation (a few words, at most one sentence). Assume that each line is added and tested one at a time.

[Hint: pay attention to the addresses in the diagram!]

  1. a[65] = 0xbb;
  2. *(b - 200) = 0;
  3. *(b + 0x344) = 5;
  4. *(((int*)c) + 16) = 0;

6. Caching I/O (9 points) #

Akshay and Cash are each implementing Caching I/O. Their implementations both use a cache size of 8 bytes and follow the same general behavior, but differ in how they handle io300_seek:

  • In Akshay’s design, when the user calls io300_seek for a position outside the cache, it fetches 8 bytes into the cache starting from the position specified by the user
  • In Cash’s design (Cash’s cache 🙂), the data fetched on io300_seek depends on the direction of the user’s seek calls: if a user seeks to an index smaller than their previous one, it will fetch the 8 bytes of the file before that index (since they are moving backward); if a user seeks to an index greater than their previous one, it will pre-fetch 8 bytes after that index.

QUESTION 6A Consider each of the performance benchmarks listed below: would Akshay’s or Cash’s design perform better than the other, or would they be roughly equivalent? For each benchmark, write your answer as “Akshay” or “Cash” or “equivalent” and briefly explain your reasoning.

[Hint: You may want to go look at the code for each benchmark, in your Caching I/O code or the stencil repository!]

  1. block_cat
  2. reverse_block_cat
  3. stride_cat

Answers:

7. Stack (9 points) #

Jennifer and Bhavani created a diagram of the stack and the value of the register %rbp for the following program at the position marked in the code. They also started labeling the addresses of some items on the stack.

Assume that the code was compiled without optimizations and with the base pointer (%rbp) turned on. Also assume that the diagram is correct, and that the code contains no errors.

 1 int combine(int num1, int num2) {
 2     return num1 * num2;
 3 }
 4 
 5 int check_nums(int x, int y) {
 6     int total = combine(x,  y);
 7
 8     // *** STACK DIAGRAM DRAWN FROM THIS POINT ***
 9     if (total > 100) {
10         return 1;
11     } else {
12         return 0;
13     }
14 }
15 
16 int main() {
17     int a = 5;
18     int b = 10;
19     int is_ok = check_nums(a, b);
20     printf("Check:  %d\n", is_ok);
21     return is_ok;
22 }

QUESTION 7A Which line of the C code would contain the instruction referenced by the return address shown in the diagram? Write your answer as “line X” and briefly explain your reasoning (a few words, max 1 sentence).

QUESTION 7B Which of the following options could be the address stored in the stored %rbp value shown in the diagram? Choose one option and briefly explain your reasoning (a few words, max 1 sentence):

  • Option 1: 0x7fff_e350
  • Option 2: 0x7fff_e360
  • Option 3: 0x7fff_e370
  • Option 4: 0x7fff_e380

QUESTION 7C Jennifer has many numbers to check and wants to restructure the main function to read in pairs of numbers from a file and call check_nums on each pair using a loop. Since she has a lot of numbers to check, she’s concerned that calling check_nums so many times will use too much stack memory. Should Jennifer be concerned? Answer “yes” or “no” and explain your reasoning (around 1 sentence).

You can assume that each pair of numbers is read from the file one at a time. If you need to make additional assumptions, feel free to include them in your answer.

8. Snake: bigger food (9 points) #

Loang and Andrew want to extend their Snake project with different types of food that can be worth more than one point. To start, they propose adding a new bit flag for each type of food (e.g., food worth 1 pt, food worth 2pts, food worth 3pts), like this:

#define LAND_CELL      0b000000
#define FLAG_SNAKE     0b000001
#define FLAG_WALL      0b000010
#define FLAG_GRASS     0b000100
#define FLAG_FOOD_1PT  0b001000
#define FLAG_FOOD_2PT  0b010000
#define FLAG_FOOD_3PT  0b100000
//      ... and so on...

QUESTION 8A Similar to our Snake project, Loang and Andrew represent each board cell as type int. Using a system of bit flags as defined above, how many different point values for food could they represent? (Assume that a cell can have at most one type of food at a time.)

QUESTION 8B Loang and Andrew are not satisfied with this system and propose a new one that involves the shift operator. Instead of using the FLAG_FOOD_* definitions above, they propose determining the number of points for the food in a cell by writing the following code (for some cell c):

int food_pts = ((unsigned int)c) >> 3;

What is the maximum number of points that food could represent using this new system? To express your answer, give a number (in decimal or hex) and briefly explain your reasoning.

QUESTION 8C Andrew proposes that we can remove the cast to unsigned int and instead compute the food value like this:

int food_pts_v2 = c >> 3;

Why is this incorrect? Explain your reasoning (around 1 sentence). Assume that we want the game to use food up to the maximum number of points you found in Part B (even if it’s a really big number).

[Hint: what’s an example where the cast would produce a different result?]

9. Signed numbers (12 points) #

Kaitlyn and John are writing a program to do arithmetic operations on some numbers. However, they want to avoid invoking undefined behavior that could set their computer on fire!

To start, they write the following two functions:

int add(int a, int b) {
    return a + b;
}

int sub(int a, int b) {
    return a - b;
}

QUESTION 9A Each of the following options lists a function call with some numbers missing, and an expected result. For each option, complete the function call such that it produces the result listed. If you believe that it’s not possible to get the result without causing undefined behavior, give an example function call that produces the undefined behavior and explain why.

Your answers should take the form “add(<number>, <number>)” or “sub(<number>, <number>), UB because …” . You may write your numbers in decimal or hex, whichever you prefer.

  1. add(0xffff'fffe, ???), result 3
  2. add(0x7fff'fff8, ???), result -128
  3. sub(0xffff'ffec, ???), result -16
  4. sub(0x3fff'ffff, ???), result 15

10. CS 300/1310 Feedback (6 points) #

QUESTION 10A (3 points) If you could make one change to CS 300/1310 to improve it (other than firing the instructor and dropping the quizzes), what would you change? Any answer but no answer will receive full credit.

QUESTION 10B (3 points) What topics do you wish we had spent more time on? Any answer but no answer will receive full credit.


Creative Commons Licence This work is licensed under a Creative Commons Attribution 4.0 International License.