tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: strtonum(3) from OpenBSD?

On Fri, Jun 26, 2009 at 10:13:55PM +0100, Iain Hibbert wrote:
 >>>> If it *can* set errno on success, which is the usual convention for
 >>>> library functions,
 >>> Nonsense, that is no usual convention. Please read errno(2) and see what
 >>> it says (try the second paragraph in the DIAGNOSTICS section)
 >> Yes, precisely. Did you read your citation before posting it? (Or did
 >> you misunderstand what I wrote because you assumed I didn't know what
 >> I was talking about? :-p )
 > Yes I read it, can you explain how you translate "Successful calls never
 > set errno" into setting errno on success being the "usual convention"?

Because "successful calls never set errno" is flatly wrong?

% cat foo.c
#include <stdio.h>
#include <errno.h>

int main(void) {
   int x;

   errno = 0;
   x = puts("foo");
   printf("x: %d  errno: %d\n", x, errno);
   return 0;
% gcc -Wall -W foo.c -o foo
% ./foo 
x: 10  errno: 2

The function succeeded, and nonetheless set errno to 2. This is
perfectly expected behavior.

Using ktrace suggests that it happens because of some nonexistent
locale file.

 > > Unless strtol is specifically granted permission to clear errno to 0
 > > after calling other functions, which it isn't in C99 (don't have POSIX
 > > on hand) there's a problem.
 > The problem is worked around by the specification saying that if you want
 > to check that ERANGE is not set then you should reset errno first.

No, that does not work around the problem. C99 explicitly says that
strtol may support additional locale-specific numeric formats.
Therefore, one has to assume that such an implementation might exist,
and if so, it could easily leave trash behind in errno. While ERANGE
is maybe not that likely to occur in such circumstances, it's
certainly possible.

 > > There's also possibly an issue that C99 does not specifically say that
 > > endptr is set on the overflow failure case, so in principle one ought
 > > to test for that case before touching it. (Which is also unlike the
 > > example in strtol(3).)
 > The manpage (and the one at specifically states that
 > all the characters that are valid digits will be processed, and that
 > endptr will be set to the remaining string. I don't have any C99 but I
 > can't see such a glaring difference being used.

C99 says

   If the correct value is outside the range of representable values,
   is returned (according to the return type and sign of the value, if
   any), and the value of the macro ERANGE is stored in errno.

( #8)

It does not specify what endptr is set to, and pedantically it's
therefore undefined. One might conclude that this condition can only
apply if #5 also applies, which does define the value of
endptr, and that's certainly a reasonable interpretation, but I'm not
yet convinced it's the only possible interpretation.

 > > It's too bad they didn't define the overflow case to return with
 > > endptr pointing at a digit. That would make things a lot easier in the
 > > common cases.
 > The specification cunningly allows for overflow to be ignored in a "safe"
 > manner.


 >>>> there's no fully safe way to distinguish an overflow from a valid return
 >>>> of LONG_MAX or LONG_MIN. But if one's going to try, one should properly
 >>>> test the return value before errno, unlike the example in strtol(3).
 >>> I think so too, but it doesn't actually matter in practice as both
 >>> conditions need to be met anyway.
 >> What if some failing (and defective) internal call leaves a trap
 >> representation in errno? I can never remember if signed integers are
 >> allowed to have trap representations, but -0 on a sign/magnitude
 >> machine is a legitimate candidate.
 > Well perhaps the people who wrote the the example code took that into
 > account when they had it checking the errno value first, eh?

Did they? Some digging suggests that signed integer variables can in
fact contain trap representations, and there's nothing preventing some
bodgy locale's garbage parsing code from leaving one in errno.

Ergo, the return value should be checked first.

David A. Holland

Home | Main Index | Thread Index | Old Index