[Webinar] Streamline your web hosting managementRegister Today

x
?
Solved

consequences of writing to file handle of a closed file

Posted on 2004-11-09
14
Medium Priority
?
443 Views
Last Modified: 2010-04-15
I had a bug (since fixed), as follows.

{
   out_fp = fopen("RXCOVER.OUT", "wt");

   for (file_count = 0; file_count < 4; ++file_count)
  {
   
    fp = open_file(fn[file_count], "rb+");
 
    for each record in the file fp
      {
        read a record from fp
     
       if the record meets a certain condition, write a message to
        out_fp
      }


     fclose(fp);

     fclose(out_fp); // WRONG!! this fclose() belongs outside the
                          //  loop!!!

  } // for file_count

}

So, after the first iteration of the loop, out_fp was CLOSED,
yet I was still trying to write data to it.

Is it possible that since it was closed, that (bad) data could
have been written to fp??

Reason I ask is that a few records in fp became trashed.  When I looked to see what program I might have run at the time the datafile was last modified (17:06, 11/6/04), this program was
indeed run at that time.

Thanks
Steve
0
Comment
Question by:Stephen Kairys
  • 7
  • 2
  • 2
  • +2
14 Comments
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12539977
Why not simply put the fclose after the second for end braces?
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 12540049
Jaime,

Thanks for the quick response.

Perhaps,  though, I did not state my question clearly.
I already fixed the bug just as you correctly indicated.

What I was wondering...when the bug was still in the
program and I was running the program on my dataset,
could the above bug have caused data in FP to
become trashed.

I'm particularly suspicious b/c of the following.

1. The program writes to OUT_FP if AND ONLY IF (for the sake
of example) a status flag in the file == 100.

2. When I look at the trashed records in the data file,
at least two of them are ONE RECORD AFTER a record
with a status flag of 100.

3. So, I'm thinking, when the program attempts to write
to the closed file, that it's somehow writing to FP instead.

Does that info help you answer my question?
Thanks again!
0
 
LVL 23

Accepted Solution

by:
brettmjohnson earned 280 total points
ID: 12540521
After you closed the file, write attempts to the file will fail.
However, if you program opened another file subsequently,
it likely acquired the same file handle.  [In fact, it must do
so for stdio to work correctly.]  In that case writing through
the stale file handle could corrupt a separate file.  This is
certainly true for the level 1 I/O APIs (open, close, read, write).

With the buffered, level 2 I/O APIs (fopen, fclose, fread, fwrite),
the situation is even more complicated.  The call to fclose()
deallocates the FILE structure that was allocated via fopen().
Using the stale FILE structure adds using freed memory to
the list of problems.

0
Easily manage email signatures in Office 365

Managing email signatures in Office 365 can be a challenging task if you don't have the right tool. CodeTwo Email Signatures for Office 365 will help you implement a unified email signature look, no matter what email client is used by users. Test it for free!

 
LVL 4

Author Comment

by:Stephen Kairys
ID: 12540764
Would fprintf() be considered level 1 or level 2 i/o? That's
what I used to write to out_fp.

Now,  I did use fopen and fclose, so I know I have
some level 2 i/o there. Can I assume your comments
about Level 1 (acquiring the same file handle, etc.) still
apply?

Finally, I "reintroduced' my bug, and dumped out the
value of the file handle. (I used %ld, I assume that
was correct?)  Surely enough, when I opened
fp for the 2nd time,  its value was the same as
out_fp "used" to have

Thanks.
.
0
 
LVL 22

Expert Comment

by:grg99
ID: 12540771
One way to avoid this problem is to zap your copy of the file handle or file pointer after a close.  For example:

close( out_handle );  out_handle = -1;

or

fclose( out_file );   out_file = NULL;

----------------------

That way your program will go BOOM if it ever tries to use that file handle or pointer, instead of possibly scribbling over some other file.

0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 12540816
Well, I tried it (for both file handles) and it did NOT go boom! :)  

In addition, the debugging code I referred to above still shows
the following (I've subsituted smaller values to make
the below more readable :)  )

Opening out_fp: value of file handle is 606

Opening fp:  value of file handle is 699

close fp and set to NULL

close out_fp and set to NULL

opening fp: the value of the file handle is 606, the
same as the prev. value of out_fp

Anyhow, I'm reasonably convinced that the above
bug could have corrupted my file, but I will
try to duplicate it tomorrow.

Thanks,
steve



0
 
LVL 23

Assisted Solution

by:brettmjohnson
brettmjohnson earned 280 total points
ID: 12541314
Sorry, I can not remember where I read "level 1" and "level 2" file I/O APIs
(maybe Microsoft doc from the '80s).

Level 1 i/o uses open(), creat(), read(), write(), lseek(), close() for block access
to a file.  open() and creat() return an integer file descriptor that is passed
to the others.  Opening a file returns a file descriptor that is the lowest number
unused file descriptor.  For instance, suppose file descriptors 0-4 are open,
and you open a new file, open() will return 5.  If you close file descriptor 2,
then open a new file, open() will return 2 as the new file descriptor.  This is
how command shells effect stdio redirection.

Level 2 i/o uses fopen(), popen(), fread(), fwrite(), fprintf(), fgets() etc, for buffered
stream access to files.  fopen() and popen() return a pointer to a FILE structure
which is used in the remaining calls.  The file structure contains the buffered
state, making it easier to read lines, individual characters, getc, ungetc, etc.
The level 2 suite uses the level 1 calls to provide the underlying access to the file,
and the file descriptor is stored in a member of the FILE structure.  If the system
fclose() does not set the embedded file descriptor to -1 after closing the file, the
structure will contain a stale file descriptor.  I would not expect fclose() to take
this precaution since it will immediately deallocate the FILE structure itself.

If you closed the file with fclose(), AND opened another file which would reuse
the previous integer file desciptor, AND you wrote through the deallocated FILE
structure, you could corrupt the newly opened file thinking you were writing to
the previously opened file.  Note that fopen() is unlikely to reallocate the same
memory for the FILE structure, however when it calls open(), that call might
return a previously closed integer file descriptor.
0
 
LVL 16

Assisted Solution

by:PaulCaswell
PaulCaswell earned 120 total points
ID: 12542324
I'd suggest one of two possibilities:

1. The fclose is executing asynchronously. Your next attempt at writing to the closed file got in before the file was actually closed.
2. The fclose actually leaves the file open, just marking the file as closed. This might be a form of cacheing to speed up the case where you open the file again soon after.

It is quite possible to open a file, close it and open it again and discover that the file handle is the same. Especially on a windoze system where there are usually only about 10 file handles available to you by default anyway.

Generally speaking, whenever you close a file, set the handle to NULL. If only the old ANSI people had specified that fclose returned 'NULL' there would now be loads of much safer code out there that says:

FILE * fp = fopen ( ... );

...

fp = fclose ( fp ); // This is illegal but I wish it wasnt.


Paul
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 12545786
Well, I just tried to re-create/duplicate the bug. w/o success.

Even though the file handle of the data file that was corrupted (FP) DOES have the same value
as the file handle of the output file (out_fp) that was closed, I'm not seeing the trashed
data I expected, nor is the timestamp of the data file being updated.

Is it possible  this behavior is random?

Thanks
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 12545988
Further update:

Now, I duplicated it.

I removed setting the file handles to NULL and now I can recreate the bug. Saw it happen
right before my eyes.  The timestamps on the 3 files being processed after the mistaken
close got updated, and the data indeed got trashed.

I'm actually relieved. This bug was in a stand-alone utilty I had written for internal testing.
I'd much rather the bug be there, as opposed to in my application itself :)

0
 
LVL 22

Expert Comment

by:grg99
ID: 12546151
Yep, this handle-aliasing error could be fixed if the C library file handles were allocated sequentially and not reused, but there's probably too much code that depends on them being small integers.

0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 12546170
So it still could be either of my suggestions.

I cant think of a way of determining which one if its either of them. Perhaps, if you are on a Windoze machine you could use FileMon.

Paul
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 12546197
So, I guess when I was dumping out my file handles,
I should have use %d instead of %ld?
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 12548776
OK. I'm satisfied that the bug in this utility program caused the other file to be trashed.
Closing issue, and thanks to everyone for their help!
0

Featured Post

Easily manage email signatures in Office 365

Managing email signatures in Office 365 can be a challenging task if you don't have the right tool. CodeTwo Email Signatures for Office 365 will help you implement a unified email signature look, no matter what email client is used by users. Test it for free!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.
Suggested Courses

612 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question