Skip to content

Commit 2fef8fd

Browse files
author
Daniel Kroening
authored
Merge pull request diffblue#1772 from tautschnig/fix-1771
Bounds checks in fgets, read
2 parents 0d0dca4 + bc0ebd3 commit 2fef8fd

File tree

5 files changed

+76
-23
lines changed

5 files changed

+76
-23
lines changed

regression/cbmc/fgets1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ main.c
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
77
\[main.assertion.3\] assertion p\[1\]=='b': FAILURE
8-
\*\* 1 of \d+ failed
8+
\*\* 2 of \d+ failed
99
--
1010
^warning: ignoring

regression/cbmc/read1/main.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifdef _WIN32
2+
#include <io.h>
3+
#else
4+
#include <unistd.h>
5+
#endif
6+
7+
#include <stdio.h>
8+
9+
int main()
10+
{
11+
char data[20];
12+
13+
if(read(0, data, 100) < 0)
14+
printf("An error has occurred");
15+
else
16+
printf("Read occurred");
17+
18+
return 0;
19+
}

regression/cbmc/read1/test.desc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--bounds-check --pointer-check --unwind 100
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
\[.*] dereference failure: pointer outside object bounds in .*: FAILURE
8+
\*\* 1 of .* failed \(.*\)
9+
--
10+
^warning: ignoring

src/ansi-c/library/stdio.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ char *fgets(char *str, int size, FILE *stream)
247247
{
248248
int str_length=__VERIFIER_nondet_int();
249249
__CPROVER_assume(str_length>=0 && str_length<size);
250+
// check that the memory is accessible
251+
(void)*(char *)str;
252+
(void)*(((const char *)str) + str_length - 1);
250253
char contents_nondet[str_length];
251254
__CPROVER_array_replace(str, contents_nondet);
252255
if(!error)

src/ansi-c/library/unistd.c

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -123,27 +123,30 @@ inline int _close(int fildes)
123123
// write to _write; this is covered by the explicit definition of
124124
// _write below
125125
#ifdef _MSC_VER
126-
#define ssize_t signed long
126+
#define ret_type int
127+
#define size_type unsigned
127128
#else
128129
#ifndef __CPROVER_SYS_TYPES_H_INCLUDED
129130
#include <sys/types.h>
130131
#define __CPROVER_SYS_TYPES_H_INCLUDED
131132
#endif
133+
#define ret_type ssize_t
134+
#define size_type size_t
132135
#endif
133136

134137
extern struct __CPROVER_pipet __CPROVER_pipes[];
135138
// offset to make sure we don't collide with other fds
136139
extern const int __CPROVER_pipe_offset;
137140

138-
ssize_t __VERIFIER_nondet_ssize_t();
141+
ret_type __VERIFIER_nondet_ret_type();
139142

140-
ssize_t write(int fildes, const void *buf, size_t nbyte)
143+
ret_type write(int fildes, const void *buf, size_type nbyte)
141144
{
142145
__CPROVER_HIDE:;
143146
if((fildes>=0 && fildes<=2) || fildes < __CPROVER_pipe_offset)
144147
{
145-
ssize_t retval=__VERIFIER_nondet_ssize_t();
146-
__CPROVER_assume(retval>=-1 && retval<=(ssize_t)nbyte);
148+
ret_type retval=__VERIFIER_nondet_ret_type();
149+
__CPROVER_assume(retval>=-1 && retval<=(ret_type)nbyte);
147150
return retval;
148151
}
149152

@@ -156,7 +159,7 @@ ssize_t write(int fildes, const void *buf, size_t nbyte)
156159
sizeof(__CPROVER_pipes[fildes].data) >=
157160
__CPROVER_pipes[fildes].next_avail+nbyte)
158161
{
159-
for(size_t i=0; i<nbyte; ++i)
162+
for(size_type i=0; i<nbyte; ++i)
160163
__CPROVER_pipes[fildes].data[i+__CPROVER_pipes[fildes].next_avail]=
161164
((char*)buf)[i];
162165
__CPROVER_pipes[fildes].next_avail+=nbyte;
@@ -169,17 +172,20 @@ ssize_t write(int fildes, const void *buf, size_t nbyte)
169172
/* FUNCTION: _write */
170173

171174
#ifdef _MSC_VER
172-
#define ssize_t signed long
175+
#define ret_type int
176+
#define size_type unsigned
173177
#else
174178
#ifndef __CPROVER_SYS_TYPES_H_INCLUDED
175179
#include <sys/types.h>
176180
#define __CPROVER_SYS_TYPES_H_INCLUDED
177181
#endif
182+
#define ret_type ssize_t
183+
#define size_type size_t
178184
#endif
179185

180-
ssize_t write(int fildes, const void *buf, size_t nbyte);
186+
ret_type write(int fildes, const void *buf, size_type nbyte);
181187

182-
inline ssize_t _write(int fildes, const void *buf, size_t nbyte)
188+
inline ret_type _write(int fildes, const void *buf, size_type nbyte)
183189
{
184190
__CPROVER_HIDE:;
185191
return write(fildes, buf, nbyte);
@@ -191,42 +197,54 @@ inline ssize_t _write(int fildes, const void *buf, size_t nbyte)
191197
// read to _read; this is covered by the explicit definition of _read
192198
// below
193199
#ifdef _MSC_VER
194-
#define ssize_t signed long
200+
#define ret_type int
201+
#define size_type unsigned
195202
#else
196203
#ifndef __CPROVER_SYS_TYPES_H_INCLUDED
197204
#include <sys/types.h>
198205
#define __CPROVER_SYS_TYPES_H_INCLUDED
199206
#endif
207+
#define ret_type ssize_t
208+
#define size_type size_t
200209
#endif
201210

202211
extern struct __CPROVER_pipet __CPROVER_pipes[];
203212
// offset to make sure we don't collide with other fds
204213
extern const int __CPROVER_pipe_offset;
205214

206215
__CPROVER_bool __VERIFIER_nondet___CPROVER_bool();
207-
ssize_t __VERIFIER_nondet_ssize_t();
216+
ret_type __VERIFIER_nondet_ret_type();
217+
size_type __VERIFIER_nondet_size_type();
208218

209-
ssize_t read(int fildes, void *buf, size_t nbyte)
219+
ret_type read(int fildes, void *buf, size_type nbyte)
210220
{
211221
__CPROVER_HIDE:;
212222
if((fildes>=0 && fildes<=2) || fildes < __CPROVER_pipe_offset)
213223
{
214-
ssize_t nread=__VERIFIER_nondet_ssize_t();
215-
__CPROVER_assume(0<=nread && (size_t)nread<=nbyte);
224+
ret_type nread=__VERIFIER_nondet_ret_type();
225+
__CPROVER_assume(0<=nread && (size_type)nread<=nbyte);
216226

227+
__CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool();
217228
#if 0
218-
size_t i;
229+
size_type i;
219230
for(i=0; i<nbyte; i++)
220231
{
221232
char nondet_char;
222233
((char *)buf)[i]=nondet_char;
223234
}
224235
#else
225-
char nondet_bytes[nbyte];
226-
__CPROVER_array_replace((char*)buf, nondet_bytes);
236+
if(nbyte>0)
237+
{
238+
size_type str_length=__VERIFIER_nondet_size_type();
239+
__CPROVER_assume(error ? str_length<=nbyte : str_length==nbyte);
240+
// check that the memory is accessible
241+
(void)*(char *)buf;
242+
(void)*(((const char *)buf) + str_length - 1);
243+
char contents_nondet[str_length];
244+
__CPROVER_array_replace((char*)buf, contents_nondet);
245+
}
227246
#endif
228247

229-
__CPROVER_bool error=__VERIFIER_nondet___CPROVER_bool();
230248
return error ? -1 : nread;
231249
}
232250

@@ -237,7 +255,7 @@ ssize_t read(int fildes, void *buf, size_t nbyte)
237255
__CPROVER_atomic_begin();
238256
if(!__CPROVER_pipes[fildes].widowed)
239257
{
240-
for(size_t i=0; i<nbyte &&
258+
for(size_type i=0; i<nbyte &&
241259
__CPROVER_pipes[fildes].next_unread <
242260
__CPROVER_pipes[fildes].next_avail;
243261
++i)
@@ -258,17 +276,20 @@ ssize_t read(int fildes, void *buf, size_t nbyte)
258276
/* FUNCTION: _read */
259277

260278
#ifdef _MSC_VER
261-
#define ssize_t signed long
279+
#define ret_type int
280+
#define size_type unsigned
262281
#else
263282
#ifndef __CPROVER_SYS_TYPES_H_INCLUDED
264283
#include <sys/types.h>
265284
#define __CPROVER_SYS_TYPES_H_INCLUDED
266285
#endif
286+
#define ret_type ssize_t
287+
#define size_type size_t
267288
#endif
268289

269-
ssize_t read(int fildes, void *buf, size_t nbyte);
290+
ret_type read(int fildes, void *buf, size_type nbyte);
270291

271-
inline ssize_t _read(int fildes, void *buf, size_t nbyte)
292+
inline ret_type _read(int fildes, void *buf, size_type nbyte)
272293
{
273294
__CPROVER_HIDE:;
274295
return read(fildes, buf, nbyte);

0 commit comments

Comments
 (0)