Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001830 [1003.1(2016/18)/Issue7+TC2] System Interfaces Editorial Enhancement Request 2024-05-03 06:55 2024-05-20 16:10
Reporter lacos View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Resolved  
Name László Érsek
Organization
User Reference
Section pwrite, write
Page Number ?
Line Number ?
Interp Status ---
Final Accepted Text Note: 0006786
Summary 0001830: off-by-one error regarding offset maximum
Description (Sorry for not providing page and line numbers; I've not been following POSIX development for a good while, and don't remember where I could download a PDF version.)

The open() specification contains:

"The largest value that can be represented correctly in an object of type off_t shall be established as the offset maximum in the open file description."

The write() / pwrite() spec states the following, *consistently* with the open() spec:

"""
[EFBIG]
    The file is a regular file, nbyte is greater than 0, and the starting position is greater than or equal to the offset maximum established in the open file description associated with fildes.
"""

However, the write() / pwrite() spec also states the following, *inconsistently* with the above references:

"For regular files, no data transfer shall occur past the offset maximum established in the open file description associated with fildes."

This last statement is not strict enough; a data transfer even precisely *at* the offset maximum, not just past it, should not occur. Otherwise, the resultant offset will not be representable in off_t.

Footnote 1: for simplicity, assume that off_t is identical to int8_t; in that case, the off_t maximum, hence the offset maximum, is 127. If we allowed

  lseek(fd, 127, SEEK_SET);
  write(fd, "X", 1);

to succeed, then the next call to

  lseek(fd, 0, SEEK_CUR);

would have to fail with -1/EOVERFLOW. The EFBIG description in write() actually forbids the above write() from succeeding -- correctly so --, however the "no data transfer shall occur past the offset maximum" language would permit this write() to succeed (because the data transfer would occur precisely *at* the offset maximum), and that's what's wrong.)

Footnote 2: this is an interesting difference from pointer arithmetic in the C standard. In, C, the following is valid:

  char x[10];
  char *p;

  p = x + 9;
  *p++ = 'X';
  p;

That is, pointing one past the array is valid -- evaluating such a pointer is valid (while dereferencing it is undefined behavior). In contrast, with the file position, we cannot point one past the max representable off_t, and therefore we cannot transfer to/from the byte in the file *at* the max representable off_t.
Desired Action In write()/pwrite(), change

"For regular files, no data transfer shall occur past the offset maximum established in the open file description associated with fildes."

to

"For regular files, no data transfer shall occur at or past the offset maximum established in the open file description associated with fildes."
Tags tc1-2024
Attached Files

- Relationships

-  Notes
(0006778)
geoffclare (manager)
2024-05-13 09:10

This seems to be a difference in understanding of what the standard means when it refers to data transfer past a given offset.

My understanding matches the way I believe that the author(s) of that text intended it to be read. Taking the example of offset 127, to me this code:

lseek(fd, 127, SEEK_SET);
write(fd, "X", 1);

results in data transfer past the offset 127, because the new offset is 128 which is greater than 127.

It appears that other people understand the phrase differently.

This should be solved by changing the phrasing to something that can't be understood in different ways. For example:
For regular files, no data transfer shall occur that would result in the file offset being set to a value greater than the offset maximum established in the open file description associated with fildes.
(0006784)
lacos (reporter)
2024-05-19 10:20

The proposed update entirely clarifies the requirement for write(), however I think it applies less to pwrite() than before, because pwrite() does not change the file offset at all.

(In retrospect, I suspect the original "data transfer [...] past the offset maximum" language may have specifically aimed at covering pwrite() at the same time as write().)

Can we perhaps use semi-formal syntax, such as:

"For regular files, no data transfer shall occur such that, using zero-based byte offsets, /byte[offmax]/ of the file, or any byte thereafter, be overwritten, where offmax is the offset maximum established in the open file description associated with fildes."
(0006785)
lacos (reporter)
2024-05-19 10:26

My reason for covering pwrite() as well is the following: an application may maintain a separate off_t variable for recording the exclusive end offset of a successful pwrite() call -- effectively the same offset to which an equivalent write() call would set the file offset inside the underlying open file description. Given that the spec intends to prevent the file offset inside the open file description from overflowing upon a write(), the same guarantee should be extended to an application that captures the same "exclusive end of successful data transfer" concept in an off_t object.
(0006786)
geoffclare (manager)
2024-05-20 08:16

Good catch that my proposed fix doesn't work for pwrite(). Having looked into it some more, I notice that the wording of the associated EFBIG error works fine for both:
[EFBIG]
The file is a regular file, nbyte is greater than 0, and the starting position is greater than or equal to the offset maximum established in the open file description associated with fildes.

So I think the text in the description should be worded in a similar way. The only difference is that the description needs to allow for writes that start before the offset maximum but would extend beyond it (if all requested bytes were written).

Change:
For regular files, no data transfer shall occur past the offset maximum established in the open file description associated with fildes.
to:
For regular files, no data shall be written at positions greater than or equal to the offset maximum established in the open file description associated with fildes. If the starting position is greater than or equal to the offset maximum (and nbyte is greater than 0), the request shall fail; otherwise, only as many bytes as there is room for shall be written.
(0006787)
lacos (reporter)
2024-05-20 09:08

Perfect, thanks!

- Issue History
Date Modified Username Field Change
2024-05-03 06:55 lacos New Issue
2024-05-03 06:55 lacos Name => László Érsek
2024-05-03 06:55 lacos Section => pwrite, write
2024-05-03 06:55 lacos Page Number => ?
2024-05-03 06:55 lacos Line Number => ?
2024-05-13 09:10 geoffclare Note Added: 0006778
2024-05-19 10:20 lacos Note Added: 0006784
2024-05-19 10:26 lacos Note Added: 0006785
2024-05-20 08:16 geoffclare Note Added: 0006786
2024-05-20 09:08 lacos Note Added: 0006787
2024-05-20 16:10 geoffclare Interp Status => ---
2024-05-20 16:10 geoffclare Final Accepted Text => Note: 0006786
2024-05-20 16:10 geoffclare Status New => Resolved
2024-05-20 16:10 geoffclare Resolution Open => Accepted As Marked
2024-05-20 16:10 geoffclare Tag Attached: tc1-2024


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker