CS360 Final Exam: December 12, 2000. Question 2: Answers and Grading

Ok, this implementation of malloc() and free() has three serious problems:
  1. It doesn't pad the requested size to a multiple of eight. For that reason, once the program does malloc(x) where x is not a multiple of eight, the return value of the next malloc() call is not going to return a multiple of eight. If that is important (i.e. the pointer is going to be used for a double), then you are going to get a bus error when you use the non-aligned pointer.

    This discussion also applies to multiples of four -- if the program does malloc(x) where x is not a multiple of four, then if the return value of the next malloc() call is used for any 4-byte quantity (e.g. an integer, a float, a pointer, or any struct containing one of these), then that use will generate a bus error.

    For example, look at the following program:

    main()
    {
      char *s;
      int *i;
    
      s = (char *) malloc(3);
      i = (int *) malloc(4);
      *i = 1;
    }
    
    The last line of this program will generate a bus error with this implementation of malloc(), because the value of i will not be a multiple of 4. Remove the first malloc() and it will be a multiple of 4.

  2. Free() doesn't free anything. If the program does not call free(), then no matter. Or if the program does not do any allocation after calling free() it doesn't matter. However, if the program keeps freeing and allocating memory, this implementation of malloc() is going to use too much memory.

  3. It makes a system call for each malloc(). This is as opposed to the standard implementation of malloc(), which buffers memory to reduce the number of system calls.

On the other hand, since this version of malloc() does not pad the size, and it does not allocate the extra eight bytes of bookkeeping, it does save on memory for programs that make a lot of malloc() calls and no free()'s. This happens in the first three programs.

So, the trick of this problem was to figure out which of the above situations applied to the various programs.

Here are the answers:


Part i: Unless all the lines of the file are of lengths that are multiples of 4, one of the strdup()'s is going to call malloc() with a size that is not a multiple of four. The next call that inserts a string into a red-black tree is going to try to allocate a red-black tree node, and malloc() is going to return a pointer that is not aligned on a multiple of 4. The red-black routine that tries to access it will generate a bus error. Therefore, the most important answer here is e. Answer b is also correct, since the program never calls free(), and h is correct, since it is making lots of malloc() calls. I'll also accepted d, since of course if the input file is big enough (and all lines are multiples of four), the program will run out of memory. Of course, it would under the standard malloc() too, but I accepted d.

Part ii: Now, all the malloc()'s are going to be in multiples of 4. Why? Because the only malloc()'s are when we call jrb_insert_int(). And structs with pointers are always multiples of 4. So no So no bus error, unless we get a weird one from the standard I/O library (e.g. from printf(), when it allocates the standard I/O buffer). So, I'd accept f or g for this. As above, b and h are true, and I accepted d.

Part iii: Same as the last part. Since the doubles are held in the JRB struct, they'll be aligned.

Part iv: The only thing that cat allocates is the standard I/O buffer. That's it. Since sbrk()'s first call will be a multiple of 4, there will be no bus error. Therefore, g is correct.

Since cat only does one malloc(), the memory usage and performance of malloc() is irrelevant. And it most assuredly will not run out of memory. Therefore, the only answer is g.

Part v: Netscape is a complicated program. No doubt it will allocate something that is not a multiple of four, and that will lead to a bus error. Therefore, e is true. Since netscape is a long-lived program, it will do lots of malloc's and free's, which means that it is going to use more memory than were it using the standard malloc(), and in fact, it may well run out of memory. Therefore, a and d are true as well. Finally, it's likely to do a lot of malloc()'s, so it will perform quite a bit slower, although since netscape is largely interactive, you could argue that the system call performance is irrelevant, so I'll accept either answering h or not.

Part vi: Now here, we know exactly what malloc()'s and free()'s are being called -- the malloc() calls are in jrb_insert_int(), and the free() calls are in jrb_delete_node(). Since these are being called a lot, we're going to have very bad memory usage, and eventually we will run out of memory, even though our tree won't have many elements. Therefore, a and d are true.

Since the only malloc()'s that are being called are from jrb_insert_int(), and these will be multiples of 4 (see above), there will be no bus error: g is true.

And since we're sleeping a second between calls, the performance of the two is going to be exactly the same -- one extra system call per second is not relevant -- h is not true.

Grading

13 points total.

In all questions, you had to answer one of e, f or g. If you tried to hedge and answer both e and f, I counted you for answering e. If you answered e and g or f and g, you received nothing. Similarly, if you answered a and b, you received nothing.

Part i: 2 points for e, and one point if you hedged and said f but not e. A half point for b and a half point for h. Answering d was irrelevant, since you can make arguments either way.

Part ii: 1 point for f or g. A half point for b and a half point for h. Answering d again was irrelevant, since you can make arguments either way.

Part iii: Exact same scoring as Part ii.

Part iv: Two points for f or g. You lost a half point if you made one other answer, and a whole point if you made more than one other answer.

Part v: A half point each for a, d, e and h.

Part vi: A half point each for a and d. A whole point for f or g. You lost a half if you answered h.