CS360 Midterm Exam. March 13, 2012. James S. Plank
Answers and Grading
Question 0
There are many ways to do this with strcpy(), sprintf(), a
few for() loops, and even strcat(). If you use strcat(),
however, you must be careful, because it will result in an O(n2)
algorithm if you keep calling strcat() on the beginning of
the string that you are constructing.
My solution uses strcpy().
The whole program, which calls atos() on argv
is in q0.c:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char *atos(char **a)
{
int i, size;
char *rv;
size = 1;
for (i = 0; a[i] != NULL; i++) size += (strlen(a[i])+1);
rv = (char *) malloc(sizeof(char)*size);
size = 0;
rv[0] = '\0';
for (i = 0; a[i] != NULL; i++) {
if (i != 0) {
rv[size] = ' ';
size++;
}
strcpy(rv+size, a[i]);
size += strlen(a[i]);
}
return rv;
}
main(int argc, char **argv)
{
char *s;
s = atos(argv);
printf("%s\n", s);
}
|
Grading
This one started at 15 points, and you received deductions for the following:
- Bad prototype: 1 point
- No return value: 1 point
- Space at the beginning of the string: 1 point
- Space at the end of the string: 1 point
- Calculated size incorrectly - major: 3 points
- Calculated size incorrectly - minor: 1 point
- O(n^2) algorithm : 3 points
- Didn't calculate the size at all: 5 points
- Trying to insert spaces at the wrong place: 2 points
- Bad for loop traversing the array: 1 point
- Using realloc instead of calculating the size: 2.5 points
- Using extra malloc/free instead of calculating the size: 2.5 points
- Forgot spaces: 1 point
Question 1
lstat() gives you information about the inode of a file. In
jtar, we use lots of this information:
- We use the inode number (st.ino) to determine hard links: 2 points
- We use the mode (st.mode) to determine protection, which we set explicitly
using chmod() when we un-tar the file: 2 points
- We also use the mode to determine if a file is a symbolic link to another file: 2 points
- We also use the mode to determine if a file is a directory: 2 points
- We use the access and modification times so that they can be reset when we untar:
1.5 points for each.
- I'm not really sure if we care about the size, because we can get that from the file
itself: 0 points
Question 2
Each of these was worth a half a point.
- A: This can happen when we're fewer than sz bytes from the
end of the file: P
- B: System calls do not generate segmentation violations. When there
is a problem, they return -1. Thus, every answer that says segmentation
violation is: I
- C: See B: I
- D: If the file is opened only for writing, this is what will happen: P
- E: See B: I
- F: Completely reasonable: P
- G: If bytes are read, the operating system will return how many
were read, not -1: I
- H: Exactly what will happen if the pointer is to the void: P
- I: This is how a buffer overflow attack occurs: P
- J: If buf is legal, there should be no problem: I
- K: Read() does not care about byte alignment, and it wouldn't
cause a bus error (See B above): I
- J: See B: I
- M: This is what happens where we're at EOF: P
- N: Completely reasonable: P
- O: This may happen because the read call spills into the void. It
may work, however, because the page boundary is after the sbrk() call: P
- P: This is the normal case when everything works: P
- Q: See B: I
- R: See B: I
- S: It's possible. See I: P
- T: Completely reasonable: P
- U: See B: I
- V: That's what happens if fd is not valid: P
- W: This can happen if it points less than sz bytes from
the end of the stack: P
- X: Since the code segment is read-only, the read() call will fail: P
- Y: See B: I
Question 3
This is a matter of chasing pointers. Let's start with the first part of the code:
for (i = 0; i < 5; i++) printf("%12d ", b[i]);
printf("\n");
printf("\n");
|
Since b's value is 0xbfffdb48, b[0] is the value at that address: -1073851180.
b[1] is the value four bytes after that address, and so on. The output is:
-1073751180 -1073751176 1611 7683 42335
Now, look at the next two lines:
for (i = 0; i < 5; i++) printf("%s\n", c[i]);
printf("\n");
|
c's value is 0xbfffdb3c, so c[0] is 0xbfffdb60. Since we are printing
c[0] as a string, we print the characters starting at 0xbfffdb60 and ending with
the null character: "d|". Similarly, c[1] is 0xbfffdb68: "Binky". The output is:
d|
Binky
Luigi
FredDontonio
Dontonio
Now the next 7 lines:
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
printf("%12d ", a[i][j]);
}
printf("\n");
}
printf("\n");
|
a[0] is the value at 0xbfffdb30: 0xbfffdb4c. Since a is an (int **), we treat that as a pointer:
a[0][0] is the integer at 0xbfffdb4c: -1073751176, and
a[0][1] is the integer four bytes later: 1611.
a[0][2] is the integer four bytes after that: 7683.
a[1] is the value four bytes after 0xbfffdb30, which is at 0xbfffdb34. Its value
is 0xbfffdb54. Thus, a[1][0] is the integer at 0xbfffdb54: 7683, and a[1][1]
is four bytes later: 42335.
The output is:
-1073751176 1611 7683
7683 42335 60605
31844 40554 1802398018
Now look at the next four lines:
for (b = a[0]; b < (int *) a[0][0]; b += 2) {
printf("%12d\n", *b);
}
printf("\n");
|
This loop sets b to 0xbfffdb4c, and increments it by 8 bytes (pointer arithmetic)
on each iteration. Since a[0][0] equals 0xbfffdb78, this will iterate quite a few times:
b | *b |
0xbfffdb4c | -1073751176 |
0xbfffdb54 | 7683 |
0xbfffdb5c | 60605 |
0xbfffdb64 | 40554 |
0xbfffdb6c | 1967915129 |
0xbfffdb74 | 1684369990 |
The final part of the code sets s to 0xbfffdb60 and
t to 0xbfffdb61. At each iteration it sets s[0] to *t, and then increments
t by seven:
t | *t |
0xbfffdb61 | '|' |
0xbfffdb68 | 'B' |
0xbfffdb6f | 'u' |
0xbfffdb76 | 'e' |
0xbfffdb7d | 'n' |
0xbfffdb84 | 'z' |
Thus, s[0] is "|Buenz". The final word is the hex value at 0xbfffdb60.
This is a little tricky.
You can see that the hex value of four bytes is the hex value of the characters
in reverse order. For example 31844 is equal 0x00007c64, which is
equal to 'd', '|', '\0' and '\0'. Thus, 'd' is 0x64 and '|' is 0x7c.
This means that *b is equal to '|' (0x7c), 'B' (0x42), 'u' (0x75)
and 'e' (0x65) in reverse order: 0x6575427c.
The entire output is:
a: 0xbfffdb30
b: 0xbfffdb48
c: 0xbfffdb3c
-1073751180 -1073751176 1611 7683 42335
d|
Binky
Luigi
FredDontonio
Dontonio
-1073751176 1611 7683
7683 42335 60605
31844 40554 1802398018
-1073751176
7683
60605
40554
1967915129
1684369990
|Buenz 0x6575427c
|
To write this problem, I wrote a program that set up the stack, and then called
messy_proc(), which printed the stack and then ran as on the test. If you
run it on a lab machine, the output will be different, but it will be the same
relative to a, b, and c. The program is in
q3.c.
Grading
Each of the five sets of print statements was worth 3 points.
Question 4
The best thing to do with the question is to draw boxes around the
regions of memory, starting with 0x1c230, which is 40 bytes long.
When you're done with that, you identify the first free chunk as
0x1c280, which is 32 bytes long, and then you chase the flink
pointers to identify the rest of the free chunks. I have
done this in
Q4-Memory-Colored.jpg, where
the free chunks are blue and the allocated ones are yellow.
Once this is done, parts A and B are straightforward:
Part A:
- First free chunk: 32 bytes starting at 0x1c280.
- Second free chunk: 16 bytes starting at 0x1c348.
- Third free chunk: 24 bytes starting at 0x1c268.
- Fourth free chunk: 48 bytes starting at 0x1c2f8.
- Last free chunk: 24 bytes starting at 0x1c368.
Part B:
- 40 bytes starting at 0x1c230. malloc() returned 0xc238.
- 16 bytes starting at 0x1c258. malloc() returned 0xc260.
- 48 bytes starting at 0x1c2a0. malloc() returned 0xc2a8.
- 16 bytes starting at 0x1c2d0. malloc() returned 0xc2d8.
- 24 bytes starting at 0x1c2e0. malloc() returned 0xc2e8.
- 32 bytes starting at 0x1c328. malloc() returned 0xc330.
- 16 bytes starting at 0x1c358. malloc() returned 0xc360.
- 48 bytes starting at 0x1c380. malloc() returned 0xc388.
Part C: sbrk(0) returns the first byte after the
heap: 0x1c3b0.
Part D: Memory is paged -- therefore, the void really
doesn't start until 0x1d000 (4K pages), or at the very least 0x1c400
(1K pages). Since 0x1c3c4 is before both of those addresses, it
will complete successfully with no segmentation violation.
Grading
5 points each for parts A and B. 2 points each for C and D.