David Cook
Well-known member
I recently ran into a silent bug that I wanted to alert others to.
In my case, the code is looking for a destination drive and wants to skip remote volumes.
The little dashes on the far left side of the above image indicate where you can set a breakpoint in the debugger. Hey! Why can't I set a breakpoint in the code where I check the vMAttrib? In fact, when debugging, it skips over the code I've highlighted in yellow.
bHasExtFSVol is equal to 16 in Apple's Files.h header. (1 << bHasExtFSVol) should give me the bit mask for that, right?
Well, '1' is an int. An int is 16 bits by default in most classic Mac compiler implementation. Bits are labeled 0 to 15. So, 1 << 16 is one more bit beyond the length of an int. The compiler sees that as the value zero (all the bits are shifted outside the range of an int, leaving nothing.) volumeParms.vMAttrib & 0 is always false. The compiler just quietly removed the code since it is unreachable. Thus, no breakpoints.
I am using Metrowerks CodeWarrior 11. It does not produce a warning for the removed code, which is a bummer.
The fix is simple. Put an 'L' or 'UL' next to the 1 to indicate a long (or unsigned long) constant. That's 32 bits.
(1UL << bHasExtFSVol)
Fortunately, no one else would ever get caught by this bug!
Oops. Here is the bug in Apple's header for Movies.h. More embarrassingly, the correct syntax appears for a different value immediately below the bug.
They probably should not have used flags or bitfields longer than 16 bits. Besides avoiding this bug, shorter flag fields are easier for a human to examine. Trying to spot the 19th bit by eye is a pain.
Hope this helps,
- David
In my case, the code is looking for a destination drive and wants to skip remote volumes.
The little dashes on the far left side of the above image indicate where you can set a breakpoint in the debugger. Hey! Why can't I set a breakpoint in the code where I check the vMAttrib? In fact, when debugging, it skips over the code I've highlighted in yellow.
bHasExtFSVol is equal to 16 in Apple's Files.h header. (1 << bHasExtFSVol) should give me the bit mask for that, right?
Well, '1' is an int. An int is 16 bits by default in most classic Mac compiler implementation. Bits are labeled 0 to 15. So, 1 << 16 is one more bit beyond the length of an int. The compiler sees that as the value zero (all the bits are shifted outside the range of an int, leaving nothing.) volumeParms.vMAttrib & 0 is always false. The compiler just quietly removed the code since it is unreachable. Thus, no breakpoints.
I am using Metrowerks CodeWarrior 11. It does not produce a warning for the removed code, which is a bummer.
The fix is simple. Put an 'L' or 'UL' next to the 1 to indicate a long (or unsigned long) constant. That's 32 bits.
(1UL << bHasExtFSVol)
Fortunately, no one else would ever get caught by this bug!
Oops. Here is the bug in Apple's header for Movies.h. More embarrassingly, the correct syntax appears for a different value immediately below the bug.
They probably should not have used flags or bitfields longer than 16 bits. Besides avoiding this bug, shorter flag fields are easier for a human to examine. Trying to spot the 19th bit by eye is a pain.
Hope this helps,
- David