- Feature Articles
- CodeSOD
- Error'd
-
Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
This is TRWTF. The addendum "too much" after "think" is of no importance, and in any event isn't correct. It should be dropped in favour of "enough" or even "at all". And that's bad, because building software is a task for people who think about what they are doing.
Admin
So, two WTFs for the price of one. On the one hand, "every version is 1.0!" On the other hand, "Yeah, we'll just check if one of the strings has ran out, not like file names will get longer/shorter between versions."
I just hope that the latest "1.0" version (minus the old backup) doesn't introduce a boatload of new issues, it looks like they have plenty already.
Admin
For when your company's software is so well-written that you decide to create your own problems.
Admin
Makes me wonder what actually gets updated between software "versions"
Admin
If so, this would be serious, but I don't see it. I suppose you're referring to the lack of an explicit "*p2 != '\0'" check, but "*p2 >= '0'" (note: digit '0', which is different from and greater than NUL) also serves this purpose. So if p2 is at the end of the string, it will either (if p1 is too) reach the final return (which is fine, reading the NUL at the end of the strings), or (if p1 is a digit) reach the "return 1", otherwise "*p1 != *p2" will be true and it will reach the second-last return. It might not be the clearest control flow, but I don't see any case where p2 is incremented beyond the terminating NUL. Am I missing something?
Admin
If only there were some sort of version structure embedded in the file contents so you didn't have parse a filename.... Oh wait, that's a different operating system.
Admin
It occurs to me that this line :
might have unspecified (not undefined) behaviour, for example if you run it on a machine where
charis unsigned and, simultaneously,char,short, andintare all the same size, because the difference is calculated (regardless of anything else) asunsignedon such a machine if the compiler uses the equivalent of-funsigned-char, as there are values ofcharin such a machine that cannot be represented by anint. (Ref: https://cppreference.com/w/c/language/conversion.html#Integer_promotions) What happens next is "unspecified" rather than "undefined" because the language standards say so, but might well cause you some ... fun... (see e.g. https://cppreference.com/w/c/language/conversion.html section "Integer conversions", specifically the last bullet point, referring to ):. otherwise, if the target type is signed, the behavior is implementation-defined (which may include raising a signal).
Fortunately for us, there aren't many machines that have
bitsof(char) == bitsof(int)Addendum 2026-02-10 15:01: "referring to )" should, of course, be "referring to unsigned to signed conversions at the same size, or any physically narrowing conversion)"
Admin
Honestly just looking at this code makes me glad that most of us don't have to use C nowadays. I propbably could understand it if I wanted but actually I think even a regex would be easier than this (and string.split would probably be the most readable solution).
Admin
Are you seriously proposing to use a regex to see which of two strings is greater(1)?
(1) With a hybrid non-numeric-bits-in-asciibetic-order / numeric-bits-in-numeric-order comparison, no less.
Admin
And you could even call it a VERSIONINFO resource... ;)
Admin
Dammit, it's got buffer overruns, integer overflows, and unchecked pointers, but no null pointer derefs that I can detect. They'll have to try harder next time.
Admin
There's no buffer overrun here unless the caller has already overrun the buffer. (This function does not modify the strings in any way.)
There's definitely a possibility of integer overflows, if one or other or both of the two strings contained something like 5000000000 (five milliard, which is a bit more than the 4.3-ish milliard capacity of an int on I32 architecture. Heck, even 2.2 milliard would cause signed-int overflow which is UB. But then again, how likely are we to encounter version 1.2.2200000000 of a shared object?
The pointers are, indeed, unchecked, which leads me to say that we do, indeed, have two potential null-derefs, at the first use of
*p1and the first use of*p2.Admin
I meant that it'll do a read-overrun of the buffer into unallocated (or at least unknown) space, presumably triggering a segfault or other protection violation.
Admin
How do you reason that?
My analysis says that it stops when it reaches the end of string "p1", of necessity given the outermost loop, and it stops analysing numbers when the relevant string contains a non-digit (and
'\000', no matter if you use one, two, or three zeros, is a non-digit).So how can it escape from one or other of the strings?
Admin
If we are inside the loop,
*p1is not'\0', If*p1is not an ASCII numeric and*p2is'\0'the following branch will execute and leave the loopIf
*p1is an ASCII numeric and*p2is'\0'then theelsebranch of this conditional will be takenAll paths through the loop where
*p2is'\0'end in areturnthus exiting the loop and the function.Addendum 2026-02-12 07:00: In the "comparison nonsense,
p2is advanced but it starts out non nul and thewhilenever advances it beyond thenul. The worst case scenario is it is pointing at anutat the end of the inner loop and the next iteration of the outer loop will take care of it safely.Addendum 2026-02-12 07:01: Sorry about all the typos in the addendum