| Main |

June 30, 2006

Writing the '*' in the wrong place (a.k.a. Bjarne Stroustrup, you are wrong!)

For some time now, it's bothered me that a lot of people are being taught to write

int* a;

rather than

int *a;

The problem, as any experienced C programmer should be able to tell you, comes when you write

int* a, b;

Unfortunately, the interpretation implied by the spacing is that a and b are both pointers to integers. This is not, however, the case; instead, a is a pointer to an int, whilst b is an int.

The way the compiler reads this declaration mirrors the way that C programmers tend to write these kinds of statements:

int *a, b;

where it is obvious from the spacing that *a is an int (which implies that a is a pointer to an int) and b is an int.

The point is that the green part is the type, whilst the things you are declaring are the blue parts. The type of the resulting variable a is certainly pointer-to-int, but the declaration to the C compiler does not say that, it just says that *a is an int, and to get the type of a, you have to read outwards from the variable name. This way of reading declarations works for all C and C++ declarations. The other way does not, forcing people to treat declarations like "int* a" as a special case.

Writing things in such a way that a human being will read them differently to the compiler is just plain wrong. You can't (as Bjarne Stroustrup tries to) justify it by saying that people shouldn't write multiple variable declarations on a line—the C syntax (like that of C++) is perfectly clear and very easy to understand, provided you don't try to space it as if it was e.g. Pascal.

It's particularly telling that you can (if you like) write declarations using additional parentheses, like this:

int (*a);
int b, (*c), d;

though you can't write

(int*) a;

(Well, not as a declaration, anyway…)

Of course, this syntax isn't normally used by macho parenthesis-hating C programmers :-)

Anyway, consider this a plea, particularly to teachers of C and C++ programming: Please don't teach your students to write 'int* a'. It isn't how the compiler reads it, and you will only make things more confusing for them.

Finally, for those people who like a puzzle, here's an interesting declaration to decipher:

int (*(*fn)(const char *n))(int a, int b);

and you can award yourself extra brownie points for knowing—without using typedef or any pre-processor macros—how to write a function definition, a pointer to which could be assigned to a variable like the one above.

(Hint: think where you're supposed to start reading the declaration to work out the type of fn.)

June 28, 2006

OS X 10.4.7

Having just criticised Apple for one thing, I'm going to add some praise for another. OS X 10.4.7 is a huge improvement for people like me whose home directories are mounted over AFP. I no longer get an enormous delay when I log in before I can do anything, which is great, and it seems (touch wood) to be more robust than it was before.

(Of course, just after I decided to write that, mdimportserver crashed…)

OS X authentication dialogs can lie(!)

Some time ago now, in fact in November of 2003, I reported to Apple that it was possible to make the authentication dialog lie about which program was asking for authorisation to do something. This is filed as rdar://3486235, for any Apple employees watching.

Here's an amusing demonstration:

SteveJobs.png

(the program that did this was definitely not called “Steve Jobs”)

Very funny, but quite scary because it means it's much too easy to trick an end-user into giving a potentially malicious program root privileges. Apple have been widely—and, to my mind, rather unfairly—lambasted for their attitude towards security holes, but in this case I'm sorry to report that the critics are quite correct. I'm sure they'll fix this now I've published it on the Internet, but I really shouldn't have had to do this; it should have been fixed back in 2003 when it was first reported.

Update: Allan Odgaard has quite rightly pointed out that even with this fixed, it is currently possible for a third-party program to replicate the look and UI of the system authentication dialog. This is true and is another problem that should really be addressed; reserving a particular key combination and making it always go to the system rather than user apps is one way around that issue (that's what Windows does, for instance).

Another, perhaps better approach might be to have the Security Server share some secret with the user, and present that in the authentication dialog to prove that it really is the Security Server and not some bogus process.

Continue reading “OS X authentication dialogs can lie(!)” $raquo;

June 19, 2006

I/O errors and bad blocks

It was quite interesting reading Jonathan Rentzsch's post about I/O errors and the impact that they might have on ordinary users.

As my company makes disk utility software, we see quite a lot of these kinds of errors, which users often report to us as “bugs”, telling us that they've checked the disk with DiskWarrior and it's fine. Of course, DiskWarrior doesn't actually check for bad blocks, which is where their mistake lies, so we end up having to explain that the problem is that our product stopped because it found something it couldn't read, and that this was caused by a problem with their hard disk.

Unfortunately for us—though perhaps fortunately for most users—because of the way that modern disks “fix” them if you overwrite the bad area, together with the very large amounts of data held on disks that are infrequently accessed, the actual frequency is somewhat hidden and tends only to show up if you write applications like backup programs or defragmentation tools, both of which need to read a large proportion of the files on the disk.

Anyway, Jonathan, in his post, takes the hacker's approach of trying to copy as much of the file as possible and for the bits that can't be copied, ignore the errors and pretend the data was zero. This is fine for people like Jonathan, or like me, who understand about disks and computer programs and know the kinds of problems this might create. However, very few people in the general user population should really be trying to use tricks like overwriting blocks with zeroes or copying the file with options set to ignore the I/O error, since the consequences of those actions are not always wholly predictable.

To give an example, imagine that the document that has developed a bad block contains important financial information, and let's also suppose that replacing the bad region with zeroes "fixes" it to the extent that the current version of whatever program wrote it is able to read it. Unfortunately, however, that does not mean that future versions will be able to read it, even if you use the “Save As…” option to save an entirely new copy of the data. So in five years' time, when the IRS or (if, like me, you're in the U.K.) HMRC inquire about the information contained therein, you might not be able to read it!

And in case you don't think that problem is real, I've seen similar problems in the past that were caused by bugs in earlier versions that sometimes resulted in subtly corrupted documents, which crashed later versions of the same program when you try to load them.

What should you do?

Keep adequate backups.

That way, when this happens (and it is, I am afraid, a question of when rather than if), you can simply restore the affected file from a recent backup.

If you don't have a back-up of the file, leave this kind of futzing with files to expert users. If you don't know any expert users, then either:

  1. Get the file so it works, and export it in plain text form (e.g. CSV, or a simple text file). Keep the plain text copy, just in case.
  2. Contact a local computer club, or (if you really must) a data recovery firm.

I've found this great program that can recover data from bad blocks…

Such programs are only marginally useful, and at worst are just snake-oil, particularly if they claim to be able to use statistics about individual bits to recover their original values (that just won't work with modern disks because of the fact that they use PRML and a Viterbi decoder; it might have worked, once upon a time, with MFM or GCR disks, and maybe even to an extent with non-PRML RLL disks, but the theory doesn't work for disks using PRML).

Backups are a much better way to keep your data safe.