Search code examples
chp-ux

c: unsigned long long being assigned wrong value on HP-UX Only


Had a bit of trouble coming up with a title for this question.

I recently fumbled in to the world of C.

I have a little bit of code that basically shows the capacity and free space of a drive. It works fine on a few different Linux distros I've tried as well as Solaris and AIX. I recently compiled on a HP-UX PA-RISC box and got (in my opinion) a really strange error.

struct statfs   fsStat;
err = statfs(rootPath,&fsStat);
unsigned long long totalBytes = (unsigned long long)(fsStat.f_bsize * fsStat.f_blocks);

In GDB when I do:

p (fsStat.f_bsize * fsStat.f_blocks)

The result is 1335205888 But after the calculation is run, when I do

p totalByes

The result is 18446744071562067968

Any information that might even give me an idea of what to try here would be really great. Used to think I knew how to program until I started doing multi platform C :(


Solution

  • Hypothesis:

    The multiplication overflowed, so fsStat.f_bsize * fsStat.f_blocks produced an overflow result of -2147483648. When this was converted to unsigned long long, it produced 18446744071562067968, which is 0xffffffff80000000, the result of wrapping -2147483648 in a 64-bit unsigned format. GDB uses different arithmetic than C, so it displayed the mathematically correct result.

    To fix this, change (unsigned long long) (fsStat.f_bsize * fsStat.f_blocks) to (unsigned long long) fsStat.f_bsize * fsStat.f_blocks, to convert to the wider integer format before multiplication.

    Better than unsigned long long would be to use either uint64_t (from <stdint.h>) or a type supplied by the platform (some Linux header) for working with disk sizes.