Skip to content

Commit 67250e5

Browse files
committed
Add caml_{read,write}_fd_exn
Prepares for resource-safety audit of io.c
1 parent 125808a commit 67250e5

File tree

6 files changed

+96
-39
lines changed

6 files changed

+96
-39
lines changed

runtime/caml/osdeps.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,30 @@ extern unsigned short caml_win32_revision;
3434
[flags] indicates whether [fd] is a socket
3535
(bit [CHANNEL_FLAG_FROM_SOCKET] is set in this case, see [io.h]).
3636
(This distinction matters for Win32, but not for Unix.)
37-
Return number of bytes read.
38-
In case of error, raises [Sys_error] or [Sys_blocked_io]. */
37+
Return number of bytes read or -1.
38+
In case of error, sets [exn] to an encoded exception value
39+
[Sys_error], [Sys_blocked_io] or an exception raised from a signal
40+
handler, if any. If the return value is -1 then [exn] contains an
41+
encoded exception. */
42+
extern int caml_read_fd_exn(int fd, int flags, void * buf, int n, value * exn);
43+
44+
/* Same as [caml_read_fd_exn], but immediately raises the exception
45+
if any, and never returns -1. */
3946
extern int caml_read_fd(int fd, int flags, void * buf, int n);
4047

4148
/* Write at most [n] bytes from buffer [buf] onto file descriptor [fd].
4249
[flags] indicates whether [fd] is a socket
4350
(bit [CHANNEL_FLAG_FROM_SOCKET] is set in this case, see [io.h]).
4451
(This distinction matters for Win32, but not for Unix.)
45-
Return number of bytes written.
46-
In case of error, raises [Sys_error] or [Sys_blocked_io]. */
52+
Return number of bytes written or -1.
53+
In case of error, sets [exn] to an encoded exception value
54+
[Sys_error], [Sys_blocked_io] or an exception raised from a signal
55+
handler, if any. If the return value is -1 then [exn] contains an
56+
encoded exception. */
57+
extern int caml_write_fd_exn(int fd, int flags, void * buf, int n, value * exn);
58+
59+
/* Same as [caml_write_fd_exn], but immediately raises the exception
60+
if any, and never returns -1. */
4761
extern int caml_write_fd(int fd, int flags, void * buf, int n);
4862

4963
/* Decompose the given path into a list of directories, and add them

runtime/caml/sys.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ CAMLnoreturn_start
3030
CAMLextern void caml_sys_error (value)
3131
CAMLnoreturn_end;
3232

33-
CAMLnoreturn_start
34-
CAMLextern void caml_sys_io_error (value)
35-
CAMLnoreturn_end;
33+
CAMLextern value caml_sys_error_exn (value);
34+
35+
CAMLextern value caml_sys_io_error_exn (value);
3636

3737
CAMLextern double caml_sys_time_unboxed(value);
3838
CAMLextern void caml_sys_init (char_os * exe_name, char_os ** argv);

runtime/io.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,15 @@ CAMLexport int caml_channel_binary_mode(struct channel *channel)
186186

187187
/* Output */
188188

189+
CAMLexport int caml_write_fd(int fd, int flags, void * buf, int n)
190+
{
191+
value exn = Val_unit;
192+
int retcode = caml_write_fd_exn(fd, flags, buf, n, &exn);
193+
caml_raise_if_exception(exn);
194+
CAMLassert(retcode > 0);
195+
return retcode;
196+
}
197+
189198
/* Attempt to flush the buffer. This will make room in the buffer for
190199
at least one character. Returns true if the buffer is empty at the
191200
end of the flush, or false if some data remains in the buffer.
@@ -283,6 +292,15 @@ CAMLexport file_offset caml_pos_out(struct channel *channel)
283292

284293
/* Input */
285294

295+
CAMLexport int caml_read_fd(int fd, int flags, void * buf, int n)
296+
{
297+
value exn = Val_unit;
298+
int retcode = caml_read_fd_exn(fd, flags, buf, n, &exn);
299+
caml_raise_if_exception(exn);
300+
CAMLassert(retcode >= 0);
301+
return retcode;
302+
}
303+
286304
/* caml_do_read is exported for Cash */
287305
CAMLexport int caml_do_read(int fd, char *p, unsigned int n)
288306
{

runtime/sys.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static char * error_message(void)
7272
#define EWOULDBLOCK (-1)
7373
#endif
7474

75-
CAMLexport void caml_sys_error(value arg)
75+
CAMLexport value caml_sys_error_exn(value arg)
7676
{
7777
CAMLparam1 (arg);
7878
char * err;
@@ -89,16 +89,20 @@ CAMLexport void caml_sys_error(value arg)
8989
memmove(&Byte(str, arg_len), ": ", 2);
9090
memmove(&Byte(str, arg_len + 2), err, err_len);
9191
}
92-
caml_raise_sys_error(str);
93-
CAMLnoreturn;
92+
CAMLreturn (caml_raise_sys_error_exn(str));
93+
}
94+
95+
CAMLexport void caml_sys_error(value arg)
96+
{
97+
caml_raise(Extract_exception(caml_sys_error_exn(arg)));
9498
}
9599

96-
CAMLexport void caml_sys_io_error(value arg)
100+
CAMLexport value caml_sys_io_error_exn(value arg)
97101
{
98102
if (errno == EAGAIN || errno == EWOULDBLOCK) {
99-
caml_raise_sys_blocked_io();
103+
return caml_raise_sys_blocked_io_exn();
100104
} else {
101-
caml_sys_error(arg);
105+
return caml_sys_error_exn(arg);
102106
}
103107
}
104108

runtime/unix.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,22 @@
7171
#define EWOULDBLOCK (-1)
7272
#endif
7373

74-
int caml_read_fd(int fd, int flags, void * buf, int n)
74+
int caml_read_fd_exn(int fd, int flags, void * buf, int n, value * exn)
7575
{
7676
int retcode;
7777
do {
78-
caml_enter_blocking_section();
78+
*exn = caml_enter_blocking_section_exn();
79+
if (Is_exception_result(*exn)) return -1;
7980
retcode = read(fd, buf, n);
80-
caml_leave_blocking_section();
81+
*exn = caml_leave_blocking_section_exn();
82+
if (Is_exception_result(*exn)) return retcode;
8183
} while (retcode == -1 && errno == EINTR);
82-
if (retcode == -1) caml_sys_io_error(NO_ARG);
84+
if (retcode == -1)
85+
*exn = caml_sys_io_error_exn(NO_ARG);
8386
return retcode;
8487
}
8588

86-
int caml_write_fd(int fd, int flags, void * buf, int n)
89+
int caml_write_fd_exn(int fd, int flags, void * buf, int n, value * exn)
8790
{
8891
int retcode;
8992
again:
@@ -92,9 +95,11 @@ int caml_write_fd(int fd, int flags, void * buf, int n)
9295
retcode = write(fd, buf, n);
9396
} else {
9497
#endif
95-
caml_enter_blocking_section();
98+
*exn = caml_enter_blocking_section_exn();
99+
if (Is_exception_result(*exn)) return -1;
96100
retcode = write(fd, buf, n);
97-
caml_leave_blocking_section();
101+
*exn = caml_leave_blocking_section_exn();
102+
if (Is_exception_result(*exn)) return retcode;
98103
#if defined(NATIVE_CODE) && defined(WITH_SPACETIME)
99104
}
100105
#endif
@@ -109,8 +114,8 @@ int caml_write_fd(int fd, int flags, void * buf, int n)
109114
n = 1; goto again;
110115
}
111116
}
112-
if (retcode == -1) caml_sys_io_error(NO_ARG);
113-
CAMLassert (retcode > 0);
117+
if (retcode == -1)
118+
*exn = caml_sys_io_error_exn(NO_ARG);
114119
return retcode;
115120
}
116121

runtime/win32.c

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ CAMLnoreturn_start
6565
static void caml_win32_sys_error (int errnum)
6666
CAMLnoreturn_end;
6767

68-
static void caml_win32_sys_error(int errnum)
68+
static value caml_win32_sys_error_exn(int errnum)
6969
{
7070
wchar_t buffer[512];
7171
value msg;
@@ -80,32 +80,43 @@ static void caml_win32_sys_error(int errnum)
8080
} else {
8181
msg = caml_alloc_sprintf("unknown error #%d", errnum);
8282
}
83-
caml_raise_sys_error(msg);
83+
return caml_raise_sys_error_exn(msg);
8484
}
8585

86-
int caml_read_fd(int fd, int flags, void * buf, int n)
86+
static void caml_win32_sys_error (int errnum)
87+
{
88+
caml_raise_if_exception(caml_win32_sys_error_exn(errnum));
89+
}
90+
91+
int caml_read_fd_exn(int fd, int flags, void * buf, int n, value * exn)
8792
{
8893
int retcode;
8994
if ((flags & CHANNEL_FLAG_FROM_SOCKET) == 0) {
90-
caml_enter_blocking_section();
95+
*exn = caml_enter_blocking_section_exn();
96+
if (Is_exception_result(*exn)) return -1;
9197
retcode = read(fd, buf, n);
9298
/* Large reads from console can fail with ENOMEM. Reduce requested size
9399
and try again. */
94100
if (retcode == -1 && errno == ENOMEM && n > 16384) {
95101
retcode = read(fd, buf, 16384);
96102
}
97-
caml_leave_blocking_section();
98-
if (retcode == -1) caml_sys_io_error(NO_ARG);
103+
*exn = caml_leave_blocking_section_exn();
104+
if (Is_exception_result(*exn)) return retcode;
105+
if (retcode == -1)
106+
*exn = caml_sys_io_error_exn(NO_ARG);
99107
} else {
100-
caml_enter_blocking_section();
108+
*exn = caml_enter_blocking_section();
109+
if (Is_exception_result(*exn)) return -1;
101110
retcode = recv((SOCKET) _get_osfhandle(fd), buf, n, 0);
102-
caml_leave_blocking_section();
103-
if (retcode == -1) caml_win32_sys_error(WSAGetLastError());
111+
*exn = caml_leave_blocking_section();
112+
if (Is_exception_result(*exn)) return retcode;
113+
if (retcode == -1)
114+
*exn = caml_win32_sys_error_exn(WSAGetLastError());
104115
}
105116
return retcode;
106117
}
107118

108-
int caml_write_fd(int fd, int flags, void * buf, int n)
119+
int caml_write_fd_exn(int fd, int flags, void * buf, int n, value * exn)
109120
{
110121
int retcode;
111122
if ((flags & CHANNEL_FLAG_FROM_SOCKET) == 0) {
@@ -114,20 +125,25 @@ int caml_write_fd(int fd, int flags, void * buf, int n)
114125
retcode = write(fd, buf, n);
115126
} else {
116127
#endif
117-
caml_enter_blocking_section();
128+
*exn = caml_enter_blocking_section_exn();
129+
if (Is_exception_result(*exn)) return 0;
118130
retcode = write(fd, buf, n);
119-
caml_leave_blocking_section();
131+
*exn = caml_leave_blocking_section_exn();
132+
if (Is_exception_result(*exn)) return retcode;
120133
#if defined(NATIVE_CODE) && defined(WITH_SPACETIME)
121134
}
122135
#endif
123-
if (retcode == -1) caml_sys_io_error(NO_ARG);
136+
if (retcode == -1)
137+
*exn = caml_sys_io_error_exn(NO_ARG);
124138
} else {
125-
caml_enter_blocking_section();
139+
*exn = caml_enter_blocking_section_exn();
140+
if (Is_exception_result(*exn)) return 0;
126141
retcode = send((SOCKET) _get_osfhandle(fd), buf, n, 0);
127-
caml_leave_blocking_section();
128-
if (retcode == -1) caml_win32_sys_error(WSAGetLastError());
142+
*exn = caml_leave_blocking_section_exn();
143+
if (Is_exception_result(*exn)) return retcode;
144+
if (retcode == -1)
145+
*exn = caml_win32_sys_error_exn(WSAGetLastError());
129146
}
130-
CAMLassert (retcode > 0);
131147
return retcode;
132148
}
133149

0 commit comments

Comments
 (0)