Toasteplex, libburn, and 64 bit file offsets

When I originally coded Toasteplex, it was (and currently still is) nothing more than a front-end to cdrecord and growisofs. Each burner would have it’s own instance of whichever program was being used at the time. Since then, I’ve found a nice-looking burning library for Linux called libburn, which is part of the libburnia project.

llibburn comes with an example called libburner, which shows basic usage of the library and how to burn/blank/format discs. From that, I wanted to make my own example program that left out all the extra command line argument processing code so I could see just the libburn function calls and how they worked. Everything went well until I went to burn my first disc with it. I kept getting an error that said it couldn’t reserve a track size of 5027876864 bytes. Strange…the iso I was burning was in fact 732909568 bytes long.

Through various searching with gdb, I found that a call to fstat in my own code returned the correct size for the .iso, and stored it in a variable of the type off_t. This is typecasted variable meant to hold file offsets. I stepped through each line after that in my own code, constantly checking the contents of the file size variable. All was well until a certain libburn function call:

burn_fd_source_new(fd, -1, fixed_size);

This assigns the file descriptor for the iso file and the image size to a burn source struct (libburn is written in c, no objects). Here is my gdb output leading up to and including the beginning of that function:

(gdb) p fixed_size
$1 = 732909568
(gdb) step
82 data_src = NULL;
(gdb)
83 if (fd>=0)
(gdb)
84 data_src = burn_fd_source_new(fd, -1, fixed_size);
(gdb) p fixed_size
$2 = 732909568
(gdb) step
burn_fd_source_new (datafd=7, subfd=-1, size=5027876864) at libburn/file.c:165

What!? 732909568 magically becomes 5027876864? Nope. No magic. Turns out the problem was libburn needed a 64 bit off_t to handle files over 2 GB. When the library was compiled, off_t was typecasted as a long long int, which is a 64 bit signed integer in Linux for a 32-bit processor. In my code, I had not specified that I needed 64 bit file offsets, so mine was only a long int, which is 32 bits. Since in the compile stage gcc only has the function declarations to look at, it has no idea that libburn wants a different kind of off_t. It just knows to make sure were using something typed as off_t. It is the already compiled library code that differs, and gcc just links to that. There isn’t any type checking at that point.

Here’s what it looks like in binary as explained to me by Thomas Schmitt (libburn developer):

732909568:
0010 1011 1010 1111 0101 0000 0000 0000

5027876864:
0000 0000 0000 0000 0000 0000 0000 0001 0010 1011 1010 1111 0101 0000 0000 0000

The extra bit there at the beginning was just part of arbitrary data on the stack. When libburn received the address of my pointer in the stack, it didn’t know I only had 32 bits available. It grabbed 64 bits starting at that address.

It turns out all I needed to fix it was add the following to the top of my source code:

#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS 64

This tells the compiler to define off_t as a long long int. I had actually figured that out on my own, but I had made a critically stupid mistake. I put this code BELOW all the system includes. They are the ones that need to see these define statements. Thomas helped me out on that, too. He said he usually defines them in the compile command line, and I realized then that it was the order that was breaking it. I should have known that.

Anyway, thanks, Thomas for all the help!

Rip Van Winkel – the sleep story

A while back I started coding a front-end for cdrecord/growisofs called Toasteplex that would allow burning multiple copies of a disc simultaneously. My dad was using it for the ministry, but had stopped for a while. Recently he’s been wanting to use it again, so I started getting the code cleaned up and fixing some bugs.

At one point in the code I was using wxWidgets thread handling code when I really should have been using native pthreads. It wasn’t a big deal to get it ported over; pretty much every function call had a one for one equivalent. During that conversion, I ran across a call to wxThread::Sleep. Pthreads doesn’t have it’s own sleep function, so I happliy replaced that call with a call to the posix standard sleep function. The original waiting time was 800 milliseconds, so wxThread::Sleep(800) became sleep(800).

Wrong!

The posix sleep function takes seconds, not milliseconds! It took me around a week to find that bug. I thought I was forgetting to unlock a mutex or a condition was never being met. Debugging a multithreaded program is terribly difficult..at least it is for me.

Just remember kids, take sleep seriously. If you’re not careful, you can go from sleeping for 800 milliseconds to sleeping for 13 minutes. That’s a long time for one iteration of a while loop. 😉