re PR libfortran/25949 (Unbounded I/O buffer memory usage for formatted IO)
2006-02-12 Janne Blomqvist <jb@gcc.gnu.org> PR libgfortran/25949 * io/io.h: Add set function pointer to struct stream. * io/unix.c (fd_seek): Only update offset, don't seek. (fd_sset): New function. (fd_read): Call lseek directly if necessary. (fd_write): Likewise. (fd_open): Set pointer to fd_sset. (mem_set): New function. (open_internal): Set pointer to mem_set. * io/transfer.c (write_block_direct): Rename to write_buf, add error return, non-pointer length argument. (unformatted_write): Update to use write_buf. (us_write): Simplify by using swrite instead of salloc_w. (write_us_marker): New function. (new_record_w): Use sset instead of memset, use write_us_marker, simplify by using swrite instead of salloc_w. From-SVN: r110895
This commit is contained in:
parent
5b0b72518b
commit
82b8244c51
4 changed files with 139 additions and 86 deletions
|
@ -1,3 +1,22 @@
|
|||
2006-02-12 Janne Blomqvist <jb@gcc.gnu.org>
|
||||
|
||||
PR libgfortran/25949
|
||||
* io/io.h: Add set function pointer to struct stream.
|
||||
* io/unix.c (fd_seek): Only update offset, don't seek.
|
||||
(fd_sset): New function.
|
||||
(fd_read): Call lseek directly if necessary.
|
||||
(fd_write): Likewise.
|
||||
(fd_open): Set pointer to fd_sset.
|
||||
(mem_set): New function.
|
||||
(open_internal): Set pointer to mem_set.
|
||||
* io/transfer.c (write_block_direct): Rename to write_buf, add
|
||||
error return, non-pointer length argument.
|
||||
(unformatted_write): Update to use write_buf.
|
||||
(us_write): Simplify by using swrite instead of salloc_w.
|
||||
(write_us_marker): New function.
|
||||
(new_record_w): Use sset instead of memset, use write_us_marker,
|
||||
simplify by using swrite instead of salloc_w.
|
||||
|
||||
2006-02-08 Francois-Xavier Coudert <coudert@clipper.ens.fr>
|
||||
|
||||
PR libfortran/25425
|
||||
|
|
|
@ -62,6 +62,7 @@ typedef struct stream
|
|||
try (*truncate) (struct stream *);
|
||||
int (*read) (struct stream *, void *, size_t *);
|
||||
int (*write) (struct stream *, const void *, size_t *);
|
||||
try (*set) (struct stream *, int, size_t);
|
||||
}
|
||||
stream;
|
||||
|
||||
|
@ -82,6 +83,8 @@ stream;
|
|||
#define sread(s, buf, nbytes) ((s)->read)(s, buf, nbytes)
|
||||
#define swrite(s, buf, nbytes) ((s)->write)(s, buf, nbytes)
|
||||
|
||||
#define sset(s, c, n) ((s)->set)(s, c, n)
|
||||
|
||||
/* The array_loop_spec contains the variables for the loops over index ranges
|
||||
that are encountered. Since the variables can be negative, ssize_t
|
||||
is used. */
|
||||
|
|
|
@ -377,22 +377,32 @@ write_block (st_parameter_dt *dtp, int length)
|
|||
}
|
||||
|
||||
|
||||
/* Writes a block directly without necessarily allocating space in a
|
||||
buffer. */
|
||||
/* High level interface to swrite(), taking care of errors. */
|
||||
|
||||
static void
|
||||
write_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes)
|
||||
static try
|
||||
write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
|
||||
{
|
||||
if (dtp->u.p.current_unit->bytes_left < *nbytes)
|
||||
generate_error (&dtp->common, ERROR_EOR, NULL);
|
||||
if (dtp->u.p.current_unit->bytes_left < nbytes)
|
||||
{
|
||||
generate_error (&dtp->common, ERROR_EOR, NULL);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
dtp->u.p.current_unit->bytes_left -= (gfc_offset) *nbytes;
|
||||
dtp->u.p.current_unit->bytes_left -= (gfc_offset) nbytes;
|
||||
|
||||
if (swrite (dtp->u.p.current_unit->s, buf, nbytes) != 0)
|
||||
generate_error (&dtp->common, ERROR_OS, NULL);
|
||||
if (swrite (dtp->u.p.current_unit->s, buf, &nbytes) != 0)
|
||||
{
|
||||
generate_error (&dtp->common, ERROR_OS, NULL);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
|
||||
*dtp->size += (GFC_INTEGER_4) *nbytes;
|
||||
{
|
||||
*dtp->size += (GFC_INTEGER_4) nbytes;
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -452,7 +462,7 @@ unformatted_write (st_parameter_dt *dtp, bt type,
|
|||
{
|
||||
size *= nelems;
|
||||
|
||||
write_block_direct (dtp, source, &size);
|
||||
write_buf (dtp, source, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -479,7 +489,7 @@ unformatted_write (st_parameter_dt *dtp, bt type,
|
|||
{
|
||||
reverse_memcpy(buffer, p, size);
|
||||
p+= size;
|
||||
write_block_direct (dtp, buffer, &sz);
|
||||
write_buf (dtp, buffer, sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1253,25 +1263,18 @@ us_read (st_parameter_dt *dtp)
|
|||
static void
|
||||
us_write (st_parameter_dt *dtp)
|
||||
{
|
||||
char *p;
|
||||
int length;
|
||||
size_t nbytes;
|
||||
gfc_offset dummy;
|
||||
|
||||
length = sizeof (gfc_offset);
|
||||
p = salloc_w (dtp->u.p.current_unit->s, &length);
|
||||
dummy = 0;
|
||||
nbytes = sizeof (gfc_offset);
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
generate_error (&dtp->common, ERROR_OS, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
memset (p, '\0', sizeof (gfc_offset)); /* Bogus value for now. */
|
||||
if (sfree (dtp->u.p.current_unit->s) == FAILURE)
|
||||
if (swrite (dtp->u.p.current_unit->s, &dummy, &nbytes) != 0)
|
||||
generate_error (&dtp->common, ERROR_OS, NULL);
|
||||
|
||||
/* For sequential unformatted, we write until we have more bytes than
|
||||
can fit in the record markers. If disk space runs out first, it will
|
||||
error on the write. */
|
||||
/* For sequential unformatted, we write until we have more bytes
|
||||
than can fit in the record markers. If disk space runs out first,
|
||||
it will error on the write. */
|
||||
dtp->u.p.current_unit->recl = max_offset;
|
||||
|
||||
dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
|
||||
|
@ -1766,6 +1769,24 @@ next_record_r (st_parameter_dt *dtp)
|
|||
}
|
||||
|
||||
|
||||
/* Small utility function to write a record marker, taking care of
|
||||
byte swapping. */
|
||||
|
||||
inline static int
|
||||
write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
|
||||
{
|
||||
size_t len = sizeof (gfc_offset);
|
||||
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
|
||||
if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE)
|
||||
return swrite (dtp->u.p.current_unit->s, &buf, &len);
|
||||
else {
|
||||
gfc_offset p;
|
||||
reverse_memcpy (&p, &buf, sizeof (gfc_offset));
|
||||
return swrite (dtp->u.p.current_unit->s, &p, &len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Position to the next record in write mode. */
|
||||
|
||||
static void
|
||||
|
@ -1785,15 +1806,10 @@ next_record_w (st_parameter_dt *dtp, int done)
|
|||
if (dtp->u.p.current_unit->bytes_left == 0)
|
||||
break;
|
||||
|
||||
length = dtp->u.p.current_unit->bytes_left;
|
||||
p = salloc_w (dtp->u.p.current_unit->s, &length);
|
||||
|
||||
if (p == NULL)
|
||||
if (sset (dtp->u.p.current_unit->s, ' ',
|
||||
dtp->u.p.current_unit->bytes_left) == FAILURE)
|
||||
goto io_error;
|
||||
|
||||
memset (p, ' ', dtp->u.p.current_unit->bytes_left);
|
||||
if (sfree (dtp->u.p.current_unit->s) == FAILURE)
|
||||
goto io_error;
|
||||
break;
|
||||
|
||||
case UNFORMATTED_DIRECT:
|
||||
|
@ -1806,37 +1822,19 @@ next_record_w (st_parameter_dt *dtp, int done)
|
|||
m = dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left;
|
||||
c = file_position (dtp->u.p.current_unit->s);
|
||||
|
||||
length = sizeof (gfc_offset);
|
||||
|
||||
/* Write the length tail. */
|
||||
|
||||
p = salloc_w (dtp->u.p.current_unit->s, &length);
|
||||
if (p == NULL)
|
||||
goto io_error;
|
||||
|
||||
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
|
||||
if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE)
|
||||
memcpy (p, &m, sizeof (gfc_offset));
|
||||
else
|
||||
reverse_memcpy (p, &m, sizeof (gfc_offset));
|
||||
|
||||
if (sfree (dtp->u.p.current_unit->s) == FAILURE)
|
||||
if (write_us_marker (dtp, m) != 0)
|
||||
goto io_error;
|
||||
|
||||
/* Seek to the head and overwrite the bogus length with the real
|
||||
length. */
|
||||
|
||||
p = salloc_w_at (dtp->u.p.current_unit->s, &length, c - m - length);
|
||||
if (p == NULL)
|
||||
generate_error (&dtp->common, ERROR_OS, NULL);
|
||||
if (sseek (dtp->u.p.current_unit->s, c - m - sizeof (gfc_offset))
|
||||
== FAILURE)
|
||||
goto io_error;
|
||||
|
||||
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
|
||||
if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE)
|
||||
memcpy (p, &m, sizeof (gfc_offset));
|
||||
else
|
||||
reverse_memcpy (p, &m, sizeof (gfc_offset));
|
||||
|
||||
if (sfree (dtp->u.p.current_unit->s) == FAILURE)
|
||||
if (write_us_marker (dtp, m) != 0)
|
||||
goto io_error;
|
||||
|
||||
/* Seek past the end of the current record. */
|
||||
|
@ -1870,13 +1868,11 @@ next_record_w (st_parameter_dt *dtp, int done)
|
|||
length = (int) (dtp->u.p.current_unit->recl - max_pos);
|
||||
}
|
||||
|
||||
p = salloc_w (dtp->u.p.current_unit->s, &length);
|
||||
if (p == NULL)
|
||||
if (sset (dtp->u.p.current_unit->s, ' ', length) == FAILURE)
|
||||
{
|
||||
generate_error (&dtp->common, ERROR_END, NULL);
|
||||
return;
|
||||
}
|
||||
memset(p, ' ', length);
|
||||
|
||||
/* Now that the current record has been padded out,
|
||||
determine where the next record in the array is. */
|
||||
|
@ -1913,13 +1909,11 @@ next_record_w (st_parameter_dt *dtp, int done)
|
|||
else
|
||||
length = (int) dtp->u.p.current_unit->bytes_left;
|
||||
}
|
||||
p = salloc_w (dtp->u.p.current_unit->s, &length);
|
||||
if (p == NULL)
|
||||
if (sset (dtp->u.p.current_unit->s, ' ', length) == FAILURE)
|
||||
{
|
||||
generate_error (&dtp->common, ERROR_END, NULL);
|
||||
return;
|
||||
}
|
||||
memset (p, ' ', length);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1937,22 +1931,14 @@ next_record_w (st_parameter_dt *dtp, int done)
|
|||
p = salloc_w (dtp->u.p.current_unit->s, &length);
|
||||
}
|
||||
}
|
||||
size_t len;
|
||||
const char crlf[] = "\r\n";
|
||||
#ifdef HAVE_CRLF
|
||||
length = 2;
|
||||
len = 2;
|
||||
#else
|
||||
length = 1;
|
||||
len = 1;
|
||||
#endif
|
||||
p = salloc_w (dtp->u.p.current_unit->s, &length);
|
||||
if (p)
|
||||
{ /* No new line for internal writes. */
|
||||
#ifdef HAVE_CRLF
|
||||
p[0] = '\r';
|
||||
p[1] = '\n';
|
||||
#else
|
||||
*p = '\n';
|
||||
#endif
|
||||
}
|
||||
else
|
||||
if (swrite (dtp->u.p.current_unit->s, &crlf[2-len], &len) != 0)
|
||||
goto io_error;
|
||||
}
|
||||
|
||||
|
|
|
@ -562,15 +562,9 @@ fd_sfree (unix_stream * s)
|
|||
static try
|
||||
fd_seek (unix_stream * s, gfc_offset offset)
|
||||
{
|
||||
if (s->physical_offset == offset) /* Are we lucky and avoid syscall? */
|
||||
{
|
||||
s->logical_offset = offset;
|
||||
return SUCCESS;
|
||||
}
|
||||
s->logical_offset = offset;
|
||||
|
||||
s->physical_offset = s->logical_offset = offset;
|
||||
|
||||
return (lseek (s->fd, offset, SEEK_SET) < 0) ? FAILURE : SUCCESS;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -606,6 +600,34 @@ fd_truncate (unix_stream * s)
|
|||
}
|
||||
|
||||
|
||||
/* Similar to memset(), but operating on a stream instead of a string.
|
||||
Takes care of not using too much memory. */
|
||||
|
||||
static try
|
||||
fd_sset (unix_stream * s, int c, size_t n)
|
||||
{
|
||||
size_t bytes_left;
|
||||
int trans;
|
||||
void *p;
|
||||
|
||||
bytes_left = n;
|
||||
|
||||
while (bytes_left > 0)
|
||||
{
|
||||
/* memset() in chunks of BUFFER_SIZE. */
|
||||
trans = (bytes_left < BUFFER_SIZE) ? bytes_left : BUFFER_SIZE;
|
||||
|
||||
p = fd_alloc_w_at (s, &trans, -1);
|
||||
if (p)
|
||||
memset (p, c, trans);
|
||||
else
|
||||
return FAILURE;
|
||||
|
||||
bytes_left -= trans;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Stream read function. Avoids using a buffer for big reads. The
|
||||
|
@ -644,7 +666,8 @@ fd_read (unix_stream * s, void * buf, size_t * nbytes)
|
|||
return errno;
|
||||
}
|
||||
|
||||
if (is_seekable ((stream *) s) && fd_seek (s, s->logical_offset) == FAILURE)
|
||||
if (is_seekable ((stream *) s) && s->physical_offset != s->logical_offset
|
||||
&& lseek (s->fd, s->logical_offset, SEEK_SET) < 0)
|
||||
{
|
||||
*nbytes = 0;
|
||||
return errno;
|
||||
|
@ -692,7 +715,8 @@ fd_write (unix_stream * s, const void * buf, size_t * nbytes)
|
|||
return errno;
|
||||
}
|
||||
|
||||
if (is_seekable ((stream *) s) && fd_seek (s, s->logical_offset) == FAILURE)
|
||||
if (is_seekable ((stream *) s) && s->physical_offset != s->logical_offset
|
||||
&& lseek (s->fd, s->logical_offset, SEEK_SET) < 0)
|
||||
{
|
||||
*nbytes = 0;
|
||||
return errno;
|
||||
|
@ -739,6 +763,7 @@ fd_open (unix_stream * s)
|
|||
s->st.truncate = (void *) fd_truncate;
|
||||
s->st.read = (void *) fd_read;
|
||||
s->st.write = (void *) fd_write;
|
||||
s->st.set = (void *) fd_sset;
|
||||
|
||||
s->buffer = NULL;
|
||||
}
|
||||
|
@ -870,6 +895,25 @@ mem_seek (unix_stream * s, gfc_offset offset)
|
|||
}
|
||||
|
||||
|
||||
static try
|
||||
mem_set (unix_stream * s, int c, size_t n)
|
||||
{
|
||||
void *p;
|
||||
int len;
|
||||
|
||||
len = n;
|
||||
|
||||
p = mem_alloc_w_at (s, &len, -1);
|
||||
if (p)
|
||||
{
|
||||
memset (p, c, len);
|
||||
return SUCCESS;
|
||||
}
|
||||
else
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mem_truncate (unix_stream * s __attribute__ ((unused)))
|
||||
{
|
||||
|
@ -932,6 +976,7 @@ open_internal (char *base, int length)
|
|||
s->st.truncate = (void *) mem_truncate;
|
||||
s->st.read = (void *) mem_read;
|
||||
s->st.write = (void *) mem_write;
|
||||
s->st.set = (void *) mem_set;
|
||||
|
||||
return (stream *) s;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue