newbie question: whats wrong with my code?

D

Daniel Rudy

At about the time of 3/24/2007 10:44 AM, Doug stated the following:
Cheers, Eric. Priceless. Did you have good diagnostics in place, or
was it a 'savage bug hunt'?

<OT>Anyone know of a decent place with similar horror stories? The
Dialy WTF isn't bad. Any others? I'm bored while waiting for my
compiler.</OT>

Doug

I had a really good one...and obscure to boot.

Kinda off-topic since this is system specific, but...

I had trouble compiling my cryptography module. It kept getting an
error about duplicating a function implementation. The reference was in
/usr/include/openssl/des.h. WTF? I wasn't even using that file as I
had my own DES library that I was using....

Turns out that the order that the header files were included changed the
problem that I was experiencing. After about a couple of hours looking
through stuff, I found the problem.

The header file for my message digest library was including
/usr/include/openssl/mdc2.h. That in turn included
/usr/include/openssl/des.h, and the crypto module includes the message
digest AND the DES library that I am using, which caused the conflict.

Lesson to be learned here? If you include various system header files,
make sure that everything in the include chain doesn't conflict with any
custom libraries/modules that you are using.

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Daniel Rudy

At about the time of 3/25/2007 5:19 AM, Harald van Dijk stated the following:
It's a BSD extension to clear the buffers (discarding the contents) of
an input or output stream. It's absolutely not standard C.

Um...Yes it is.

STANDARDS
The fflush() function conforms to ISO/IEC 9899:1990 (``ISO C90'').

And it's in my C pocket reference as standard C.


--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Daniel Rudy

At about the time of 3/25/2007 10:10 AM, Barry Schwarz stated the following:
snip
As for strncpy(3), the man page states the following:

The strncpy() function copies at most len characters from src into dst.
If src is less than len characters long, the remainder of dst is filled
with `\0' characters. Otherwise, dst is not terminated.
if (feof != 0) eof_flag = 1;
snip
if (strlen(argv[1]) > sizeof(infilename) - 2)
Why -2? If strlen() returns 5 and sizeof evaluates to 6, there is
room for the name plus the '\0'.
Call it paranoia about security. I didn't want to take the chance of
having a off-by-one error. Better to be sure now than fixing a
security problem later.
strncpy(infilename, argv[1], sizeof(infilename) - 2);
Since you know it will fit at this point, why not strcpy, which will
include the terminal '\0', eliminating the need for the next
statement?
Security Paranoia.
Does malloc() set errno? Is it required to? Shouldn't you clear
errno before the call?
Yes, and No.

No and yes actually.

If malloc returns NULL for a non 0 memory allocation request, that means
it failed, reguardless of what the error was. Usually, unless something
really bizarre happened, errno would be set to ENOMEM. I dunno about
Linux, but the BSDs and Mac OSX exhibit this behavior. I'll have to
check the man pack on a sun to see what Solaris does with it.
According to n1124:

What *IS* n1124? I see everyone referring to it, but I don't know what
it is and I don't have it.
Setting errno by malloc is neither required nor prohibited. It
may on your system but portable code cannot depend on it. (Portable
also include the next update to your library.)

Library functions are allowed to set errno even if no error
occurs.

No library function is allowed to reset errno.

Footnote 172 recommends setting errno to 0 before calling a
function if you intend to use the value after the function returns.

A little paranoia in a programmer is a good thing. But you are acting
inconsistently. You refuse to accept the documented behavior of
strncpy (propagating '\0' to fill the destination array) but are quite
willing to accept undocumented properties about errno (who sets it and
how long the values persist). Hobgoblins of small minds not
withstanding, consistency in a programmer is a very good thing.

Well, the little blurb there about strncpy says that it will behave like
that UNLESS src fills dst completely, then dst is *NOT* null terminated.
I'm doing it to make sure. Besides, *MOST* library function return
some indication that an error occurred. A value like -1 or 0, or
returns a number of bytes smaller than what was requested. That's what
I did with the fread functions.

If fread returned less than what I requested, then I checked for EOF.
If it wasn't an EOF that caused a short read, then the only thing that
it can be is an error.
snip


Not according to n1124. It is neither required nor prohibited.
Consequently, portable code cannot depend on it.


If your man page says this then it is wrong. n1124 does not state
"only" which is good because we know that fseek will also clear the
end-of-file indicator.

That was a direct quote. It must be system dependent behavior then.
Unfortunately, this has nothing to do with my question.

While feof cannot clear errno (see previous comment), it is allowed to
set it to a non-zero value. Depending on the value from fread still
being present after feof is called is non-portable.


The error indicator and errno are two completely separate topics.
Again, n1124 does not say "only".


This statement is not part of the standard. Furthermore, the standard
specifically states that errno need not be an external variable.

From your context, I cannot tell what "These functions" refer to. If
it is only ferror and feof (seems likely given the context) then it is
probably true but also irrelevant.


Not portably.


There is no fpurge in n1124. It may be posix (since you reference man
pages) but it is not standard.

I went looking for it, but I can't seem to find it outside of the
fflush(3) man page. I could have sworn it was in my C manual.
snip


The #if block is unnecessary. If you intend to keep it, you probably
need to insert a #undef before the #define.

Someone complained about that, but I guess I can take the entire
construct out and leave it as a simple #define.
#define FILENAMESIZE 1024 /* max size of filenames */




int copyfile(const char *infilename, const char *outfilename);
void cleanup(FILE *infile, FILE *outfile, void *buffer);

int main(int argc, char **argv)
{
int i; /* generic variable */
char infilename[FILENAMESIZE]; /* input filename */
char outfilename[FILENAMESIZE]; /* output filename */

/* get filenames */
if (argc != 3)
{
switch(argc)
{
case 1:
printf("Enter path/filename to copy -->");
fflush(stdout);
fpurge(stdin);

No such standard function.

I thought it was in the C manual, but I guess not. I went looking for it.
snip


You call cleanup for normal end of input and for errors on either
stream. If the error was on outfile, this fflush will probably also
fail and you will have two error messages for the same condition.

So how would you have handled it?
Slightly redundant since fclose(outfile) will automatically flush the
stream.



Remove del for email


--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Daniel Rudy

At about the time of 3/26/2007 10:41 PM, Daniel Rudy stated the following:
At about the time of 3/25/2007 5:19 AM, Harald van Dijk stated the following:

Um...Yes it is.

STANDARDS
The fflush() function conforms to ISO/IEC 9899:1990 (``ISO C90'').

And it's in my C pocket reference as standard C.

No, it's not. I stand corrected.

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Daniel Rudy

At about the time of 3/25/2007 11:55 AM, Chris Torek stated the following:
fpurge() is not Standard C (as others have noted). It is my
invention: I put it into 4.4BSD, because people keep claiming they
want a "discard data" behavior, and it did seem as though stdio
should probably have functionality similar to the "discard data"
ioctl() calls.

Unlike the non-Standard "fflush on stdin", fpurge() works in *both*
directions, which means that you have a chance to throw out
un*written* data as well as un*read* data. Like the non-Standard
"fflush on stdin", fpurge is non-Standard. :)

Wow, I didn't even know that you could do an ioclt(2) to dump the
buffers into the bit bucket. I've actually done business with WRS in
the past...buying the FreeBSD CDs. Are you still on the project? I'm
asking because I heard that Wind River discontinued BSD/OS.

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
F

Flash Gordon

Daniel Rudy wrote, On 27/03/07 06:41:
At about the time of 3/25/2007 5:19 AM, Harald van Dijk stated the following:

Um...Yes it is.

STANDARDS
The fflush() function conforms to ISO/IEC 9899:1990 (``ISO C90''). ^^^^^^^^

And it's in my C pocket reference as standard C.

fflush is standard, fpurge is not.
 
F

Flash Gordon

Daniel Rudy wrote, On 27/03/07 07:00:
At about the time of 3/25/2007 10:10 AM, Barry Schwarz stated the following:
snip
As for strncpy(3), the man page states the following:

The strncpy() function copies at most len characters from src into dst.
If src is less than len characters long, the remainder of dst is filled
with `\0' characters. Otherwise, dst is not terminated.

if (feof != 0) eof_flag = 1; snip

if (strlen(argv[1]) > sizeof(infilename) - 2)
Why -2? If strlen() returns 5 and sizeof evaluates to 6, there is
room for the name plus the '\0'.
Call it paranoia about security. I didn't want to take the chance of
having a off-by-one error. Better to be sure now than fixing a
security problem later.

strncpy(infilename, argv[1], sizeof(infilename) - 2);
Since you know it will fit at this point, why not strcpy, which will
include the terminal '\0', eliminating the need for the next
statement?

Security Paranoia.

Does malloc() set errno? Is it required to? Shouldn't you clear
errno before the call?
Yes, and No.
No and yes actually.

If malloc returns NULL for a non 0 memory allocation request, that means
it failed, reguardless of what the error was. Usually, unless something
really bizarre happened, errno would be set to ENOMEM. I dunno about
Linux, but the BSDs and Mac OSX exhibit this behavior. I'll have to
check the man pack on a sun to see what Solaris does with it.

Implementations do not the standard make. Are you going to try *all* the
compilers and libraries out there for us and tell us if the all do this?
How about the new implementation being released next week?
What *IS* n1124? I see everyone referring to it, but I don't know what
it is and I don't have it.

It is a draft of the latest C standard. See
http://clc-wiki.net/wiki/C_standardisation:ISO

Well, the little blurb there about strncpy says that it will behave like
that UNLESS src fills dst completely, then dst is *NOT* null terminated.
I'm doing it to make sure.

The code in question was guaranteed to have enough space so that unless
is irrelevant.

Someone complained about that, but I guess I can take the entire
construct out and leave it as a simple #define.

The complaint was incorrect, using a simple #define would be better.

<snip>
 
R

Richard Heathfield

Daniel Rudy said:
At about the time of 3/25/2007 10:10 AM, Barry Schwarz stated the
following:


What *IS* n1124? I see everyone referring to it, but I don't know
what it is and I don't have it.

It's a working document based on C99 + TCs 1 and 2, which presumably
will be (or is being) used as the kicking off point for C0x.

I went looking for it, but I can't seem to find it outside of the
fflush(3) man page. I could have sworn it was in my C manual.

Nah - no such function in standard C.

<snip>
 
C

Chris Torek

At about the time of 3/25/2007 11:55 AM, Chris Torek stated the following:
... I put [fpurge] into 4.4BSD ... similar to the "discard data"
ioctl() calls.

Wow, I didn't even know that you could do an ioctl(2) to dump the
buffers into the bit bucket.

Only on non-file "files" (ttys, network streams, etc).
I've actually done business with WRS in the past...buying the
FreeBSD CDs. Are you still on the project? I'm asking because
I heard that Wind River discontinued BSD/OS.

4.4BSD predated Wind River by quite a few years, coming out in 1992
or so. Wind River bought both BSDI and Walnut Creek in 2000 and
discontinued BSD/OS a few years later. (So, no, not still on that
project, since it no longer exists. :) )
 
C

CBFalconer

Daniel said:
.... snip ...

Well, the little blurb there about strncpy says that it will
behave like that UNLESS src fills dst completely, then dst is
*NOT* null terminated. I'm doing it to make sure. Besides,
*MOST* library function return some indication that an error
occurred. A value like -1 or 0, or returns a number of bytes
smaller than what was requested. That's what I did with the
fread functions.

Don't futz about with strncpy (which does the job it was designed
for, but not the job for which you want it). Just use strlcpy and
strlcat, bearing in mind the documented warnings about naming. For
a portable implementation see:

<http://cbfalconer.home.att.net/download/>
 
G

Giorgos Keramidas

Chris Torek said:
C89 and C99 differ here. Unsuffixed decimal constants in C99
have type "int", "long", or "long long", whichever is the first
one that makes the value fit. Unsuffixed decimal constants in
C89 have type "int", "unsigned int" [I think], "long", or
"unsigned long", whichever is the first one that makes the
value fit.

Practically speaking, that means that, in C89, on your typical
32-bit machine (i.e., something only 10 years old or so, or
running in compatibility mode) ... well, try the following
program:

#include <stdio.h>

int main(void) {
if (-1 > 3000000000)
puts("must be c89");
else
puts("could be c99");
return 0;
}

I note that gcc with -std=c99 gets this wrong, at least with
gcc 3.2.3:

It seems that this has been fixed with gcc 3.4.6:

% gcc -std=c89 foo.c
foo.c: In function `main':
foo.c:5: warning: this decimal constant is unsigned only in ISO C90
% ./a.out
must be c89
% gcc -std=c99 foo.c
% ./a.out
could be c99
%

The careful use of "must be ..." and "could be ..." was very
amusing too, thanks for the extremely insightful post as always :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

error 28
code 34
fread/fwrite 2 18
Whats wrong with my stream ? 4
question 33
Can not read VCD file in Linux 8
file bug 28
bsearch problem in my code 8

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,278
Latest member
BuzzDefenderpro

Latest Threads

Top