"Dear Waluigi, Your program calls f(), which prints a line then calls g(). G() in turn prints a line and calls h(). H() prints a line and then decrements the counter, whose value will be two, which means that h() will call longjmp(buf, 4). Unfortunately, setjmp() has never been called on buf, so the values to which the registers are restored or undefinied. Either a bad pc, sp or fp will cause a segmentation violation. Your output will be: Entered function = f Entered function = g Entered function = h Segmentation violation Love and kisses, Dr. Plank"
![]() |
cproc: push #4 // Allocate y mv #7 -> %r0 // Push 7 on the stack st %r0 -> [sp]-- ld [fp+12] -> %r0 // Calculate &(x[15]) mv #60 -> %r1 add %r0, %r1 -> %r0 ld [r0] -> %r0 // Dereference it and put it on the stack st %r0 -> [sp]-- jsr b // Call the subroutine & pop args pop #8 st %r0 -> [fp] // Store the return value in y ld [fp] -> %r0 // Calculate y+3 mv #3 -> %r1 add %r0, %r1 -> %r0 // Make sure the result is in r0 ret |
Grading -- one put for each of my comments above. If you didn't get the entire part, you got zero -- for example, if you called jsr but not "pop 8", you got zero for "Call the subroutine & pop args."
A bunch of you calculated x[15] before pushing 7 on the stack. While that ends up working, it's not the correct order -- arguments are calculated and pushed on the stack in reverse order. If you don't believe me, try:
#include <stdio.h>
main()
{
int i;
i = 0;
printf("%d, %d\n", i++, i++);
}
|
![]() |
Part B: To start with, x is 0x13f40 (or at least that's what I meant -- I had the printf statement before the malloc, which was wrong. I was hoping you'd assume that x started at 0x13f68. If you didn't, you still had to give a logically correct answer). The size of the allocated chunk will be 48 bytes (40 bytes plus 8 for padding), so the value 48 will be put 8 bytes before x, which is at address 0x13f38. The program will write the values 0, 40, 80, etc in each four-byte memory slot, starting with 0x13f40 and ending with 0x13f64. When it's done, x will equal 0x13f68. When free() is called on x, it will look at address 0x13f60 for the size, which will be 320. That means that free() will hook a 320-byte chunk starting at address 0x13f60 onto the free list. The value 320 will be undisturbed, but a free-list pointer will be put at 0x13f64, and potentially another will be put at 0x13f68. Since the chunk is on the free list, there will be a free list pointer pointing to that chunk. Here is the state of memory both before and after the free(x) call:
![]() |
![]() |
Part C: Now the nasty part. I can see three potential outcomes.
![]() |
#include <stdio.h>
#include <stdlib.h>
main()
{
int p[2];
char c;
pipe(p);
close(p[0]);
c = 0;
while (1) write(p[1], &c, 1);
}
|
You should have the while() loop because some operating systems will buffer a few write() calls before generating SIGPIPE (see the Signal Lecture Notes for more explanation). Some of you tried to write to a closed file descriptor -- that will not generate SIGPIPE. Intsead, the operating system will return -1 from the write() call and set errno to EBADF: "Bad file descriptor".
![]() |
Open files remain open across the execv call.
If successful, execv never returns. Why? Because the address space, in particular the stack, has been overwritten -- there's no way for it to return.
![]() |
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct {
int id;
int n;
pthread_t tid;
int *ndone;
pthread_mutex_t *lock;
pthread_cond_t *cond;
} Thread_Info;
void *thread(void *arg)
{
Thread_Info *ti;
ti = (Thread_Info *) arg;
do_random_stuff(ti);
pthread_mutex_lock(ti->lock);
if (*(ti->ndone) < ti->n-1) {
*(ti->ndone) = *(ti->ndone)+1;
pthread_cond_wait(ti->cond, ti->lock);
} else {
while (*(ti->ndone) >= 0) {
pthread_cond_signal(ti->cond);
*(ti->ndone) = *(ti->ndone)-1;
}
}
pthread_mutex_unlock(ti->lock);
do_more_random_stuff(ti);
}
main(int argc, char **argv)
{
Thread_Info *ti;
int i;
int n;
pthread_mutex_t m;
pthread_cond_t c;
int ndone;
ndone = 0;
pthread_mutex_init(&m, NULL);
pthread_cond_init(&c, NULL);
n = atoi(argv[1]);
for (i = 0; i < n; i++) {
ti = (Thread_Info *) malloc(sizeof(Thread_Info));
ti->id = i;
ti->n = n;
ti->ndone = &ndone;
ti->lock = &m;
ti->cond = &c;
pthread_create(&(ti->tid), NULL, thread, (void *) ti);
}
pthread_exit(NULL);
}
|
![]() |
UNIX> ./a.out < f4.txt UNIX> cat f2.txt 12341234 23452345 97531864 UNIX> cat f3.txt 98765432 UNIX>
![]() |