Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
frama-c
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
frama-c
Commits
b337c046
Commit
b337c046
authored
5 years ago
by
Andre Maroneze
Browse files
Options
Downloads
Patches
Plain Diff
[Libc] Fix specs in wchar.h
parent
54b20a57
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
share/libc/__fc_string_axiomatic.h
+15
-0
15 additions, 0 deletions
share/libc/__fc_string_axiomatic.h
share/libc/wchar.h
+80
-10
80 additions, 10 deletions
share/libc/wchar.h
tests/libc/wchar_h.c
+59
-1
59 additions, 1 deletion
tests/libc/wchar_h.c
with
154 additions
and
11 deletions
share/libc/__fc_string_axiomatic.h
+
15
−
0
View file @
b337c046
...
...
@@ -171,6 +171,21 @@ __BEGIN_DECLS
@ }
@*/
/*@ axiomatic WMemChr {
@ logic 𝔹 wmemchr{L}(wchar_t *s, wchar_t c, ℤ n)
@ reads s[0..n - 1];
@ // Returns [true] iff wide char array [s] contains wide character [c]
@
@ logic ℤ wmemchr_off{L}(wchar_t *s, wchar_t c, ℤ n)
@ reads s[0..n - 1];
@ // Returns the offset at which [c] appears in [s].
@
@ axiom wmemchr_def{L}:
@ \forall wchar_t *s; \forall wchar_t c; \forall ℤ n;
@ wmemchr(s,c,n) <==> \exists int i; 0 <= i < n && s[i] == c;
@ }
@*/
/*@ axiomatic WcsLen {
@ logic ℤ wcslen{L}(wchar_t *s)
@ reads s[0..];
...
...
This diff is collapsed.
Click to expand it.
share/libc/wchar.h
+
80
−
10
View file @
b337c046
...
...
@@ -41,6 +41,8 @@ __PUSH_FC_STDLIB
// ISO C requires the tag 'struct tm' (as declared in <time.h>) to be declared.
#include
"time.h"
#include
"string.h"
__BEGIN_DECLS
#ifndef WEOF
...
...
@@ -48,16 +50,35 @@ __BEGIN_DECLS
#endif
/*@
requires valid:
valid_read_or_empty((char*)s, (size_t)(sizeof(wchar_t)*n))
|| \valid_read(((unsigned char*)s)+(0..wmemchr_off(s,c,n)));
@ requires initialization:
\initialized(s+(0..n - 1))
|| \initialized(s+(0..wmemchr_off(s,c,n)));
@ requires danglingness:
non_escaping(s, (size_t)(sizeof(wchar_t)*n))
|| non_escaping(s, (size_t)(sizeof(wchar_t)*(wmemchr_off(s,c,n)+1)));
assigns \result \from s, indirect:s[0 .. n-1], indirect:c, indirect:n;
ensures result_null_or_inside_s:
\result == \null || \subset (\result, s+(0 .. n-1));
*/
extern
wchar_t
*
wmemchr
(
const
wchar_t
*
s
,
wchar_t
c
,
size_t
n
);
/*@ assigns \result \from indirect:s1[0 .. n-1], indirect:s2[0 .. n-1], indirect:n; */
/*@
requires valid_s1: valid_read_or_empty(s1, (size_t)(sizeof(wchar_t)*n));
requires valid_s2: valid_read_or_empty(s2, (size_t)(sizeof(wchar_t)*n));
requires initialization:s1: \initialized(s1+(0..n-1));
requires initialization:s2: \initialized(s2+(0..n-1));
requires danglingness:s1: non_escaping(s1, (size_t)(sizeof(wchar_t)*n));
requires danglingness:s2: non_escaping(s2, (size_t)(sizeof(wchar_t)*n));
assigns \result \from indirect:s1[0 .. n-1], indirect:s2[0 .. n-1], indirect:n;
*/
extern
int
wmemcmp
(
const
wchar_t
*
s1
,
const
wchar_t
*
s2
,
size_t
n
);
/*@
requires valid_dest: valid_or_empty(dest, (size_t)(sizeof(wchar_t)*n));
requires valid_src: valid_read_or_empty(src, (size_t)(sizeof(wchar_t)*n));
requires separation:dest:src: \separated(dest+(0 .. n-1), src+(0 .. n-1));
assigns dest[0 .. n-1] \from src[0 .. n-1], indirect:src, indirect:n;
assigns \result \from dest;
...
...
@@ -66,6 +87,8 @@ extern int wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n);
extern
wchar_t
*
wmemcpy
(
wchar_t
*
restrict
dest
,
const
wchar_t
*
restrict
src
,
size_t
n
);
/*@
requires valid_src: \valid_read(src+(0..n-1));
requires valid_dest: \valid(dest+(0..n-1));
assigns dest[0 .. n-1] \from src[0 .. n-1], indirect:src, indirect:n;
assigns \result \from dest;
ensures result_ptr: \result == dest;
...
...
@@ -73,6 +96,7 @@ extern wchar_t * wmemcpy(wchar_t *restrict dest, const wchar_t *restrict src, si
extern
wchar_t
*
wmemmove
(
wchar_t
*
dest
,
const
wchar_t
*
src
,
size_t
n
);
/*@
requires valid_wcs: \valid(wcs+(0..n-1));
assigns wcs[0 .. n-1] \from wc, indirect:n;
assigns \result \from wcs;
ensures result_ptr: \result == wcs;
...
...
@@ -82,6 +106,10 @@ extern wchar_t * wmemmove(wchar_t *dest, const wchar_t *src, size_t n);
extern
wchar_t
*
wmemset
(
wchar_t
*
wcs
,
wchar_t
wc
,
size_t
n
);
/*@
requires valid_wstring_src: valid_read_wstring(src);
requires valid_wstring_dest: valid_wstring(dest);
requires room_for_concatenation: \valid(dest+(wcslen(dest)..wcslen(dest)+wcslen(src)));
requires separation:\separated(dest+(0..wcslen(dest)+wcslen(src)),src+(0..wcslen(src)));
assigns dest[0 .. ] \from dest[0 .. ], indirect:dest, src[0 .. ], indirect:src;
assigns \result \from dest;
ensures result_ptr: \result == dest;
...
...
@@ -96,21 +124,36 @@ extern wchar_t * wcscat(wchar_t *restrict dest, const wchar_t *restrict src);
*/
extern
wchar_t
*
wcschr
(
const
wchar_t
*
wcs
,
wchar_t
wc
);
/*@ assigns \result \from indirect:s1[0 .. ], indirect:s2[0 .. ]; */
/*@
requires valid_wstring_s1: valid_read_wstring(s1); // over-strong
requires valid_wstring_s2: valid_read_wstring(s2); // over-strong
assigns \result \from indirect:s1[0 .. ], indirect:s2[0 .. ];
*/
extern
int
wcscmp
(
const
wchar_t
*
s1
,
const
wchar_t
*
s2
);
/*@
assigns dest[0 .. ] \from src[0 .. ], indirect:src, dest[0 .. ], indirect:dest;
requires valid_wstring_src: valid_read_wstring(src);
requires room_wstring: \valid(dest+(0 .. wcslen(src)));
requires separation:\separated(dest+(0..wcslen(src)),src+(0..wcslen(src)));
assigns dest[0 .. wcslen(src)] \from src[0 .. wcslen(src)], indirect:src;
assigns \result \from dest;
ensures result_ptr: \result == dest;
*/
extern
wchar_t
*
wcscpy
(
wchar_t
*
restrict
dest
,
const
wchar_t
*
restrict
src
);
/*@ assigns \result \from indirect:wcs[0 .. ], indirect:accept[0 .. ]; */
/*@
requires valid_wstring_wcs: valid_read_wstring(wcs);
requires valid_wstring_accept: valid_read_wstring(accept);
assigns \result \from indirect:wcs[0 .. ], indirect:accept[0 .. ];
*/
extern
size_t
wcscspn
(
const
wchar_t
*
wcs
,
const
wchar_t
*
accept
);
// wcslcat is a BSD extension (non-C99, non-POSIX)
/*@
requires valid_nwstring_src: valid_read_nwstring(src, n);
requires valid_wstring_dest: valid_wstring(dest);
requires room_for_concatenation: \valid(dest+(wcslen(dest)..wcslen(dest)+\min(wcslen(src), n)));
requires separation:\separated(dest+(0..wcslen(dest)+wcslen(src)),src+(0..wcslen(src)));
assigns dest[0 .. ] \from dest[0 .. ], indirect:dest, src[0 .. n-1], indirect:src, indirect:n;
assigns \result \from indirect:dest[0 .. ], indirect:src[0 .. n-1], indirect:n;
*/
...
...
@@ -118,6 +161,8 @@ extern size_t wcslcat(wchar_t *restrict dest, const wchar_t *restrict src, size_
// wcslcpy is a BSD extension (non-C99, non-POSIX)
/*@
requires valid_wstring_src: valid_read_wstring(src);
requires room_nwstring: \valid(dest+(0 .. n));
requires separation:dest:src: \separated(dest+(0 .. n-1), src+(0 .. n-1));
assigns dest[0 .. n-1] \from src[0 .. n-1], indirect:src, indirect:n;
assigns \result \from indirect:dest[0 .. n-1], indirect:dest,
...
...
@@ -125,29 +170,45 @@ extern size_t wcslcat(wchar_t *restrict dest, const wchar_t *restrict src, size_
*/
extern
size_t
wcslcpy
(
wchar_t
*
dest
,
const
wchar_t
*
src
,
size_t
n
);
/*@ requires valid_string_s: valid_read_wstring(s);
assigns \result \from indirect:s[0 .. ]; */
/*@
requires valid_string_s: valid_read_wstring(s);
assigns \result \from indirect:s[0 .. wcslen(s)];
ensures result_is_length: \result == wcslen(s);
*/
extern
size_t
wcslen
(
const
wchar_t
*
s
);
/*@
requires valid_nwstring_src: valid_read_nwstring(src, n);
requires valid_wstring_dest: valid_wstring(dest);
requires room_for_concatenation: \valid(dest+(wcslen(dest)..wcslen(dest)+\min(wcslen(src), n)));
requires separation:\separated(dest+(0..wcslen(dest)+wcslen(src)),src+(0..wcslen(src)));
assigns dest[0 .. ] \from dest[0 .. ], indirect:dest, src[0 .. n-1], indirect:src, indirect:n;
assigns \result \from dest;
ensures result_ptr: \result == dest;
*/
extern
wchar_t
*
wcsncat
(
wchar_t
*
restrict
dest
,
const
wchar_t
*
restrict
src
,
size_t
n
);
/*@ assigns \result \from indirect:s1[0 .. n-1], indirect:s2[0 .. n-1], indirect:n; */
/*@
requires valid_wstring_s1: valid_read_wstring(s1); // over-strong
requires valid_wstring_s2: valid_read_wstring(s2); // over-strong
assigns \result \from indirect:s1[0 .. n-1], indirect:s2[0 .. n-1], indirect:n;
*/
extern
int
wcsncmp
(
const
wchar_t
*
s1
,
const
wchar_t
*
s2
,
size_t
n
);
/*@
requires valid_wstring_src: valid_read_wstring(src);
requires room_nwstring: \valid(dest+(0 .. n-1));
requires separation:dest:src: \separated(dest+(0 .. n-1), src+(0 .. n-1));
assigns dest[0 .. n-1] \from src[0 .. n-1], indirect:src, indirect:n;
assigns \result \from dest;
ensures result_ptr: \result == dest;
ensures initialization: \initialized(dest+(0 .. n-1));
*/
extern
wchar_t
*
wcsncpy
(
wchar_t
*
restrict
dest
,
const
wchar_t
*
restrict
src
,
size_t
n
);
/*@
requires valid_wstring_wcs: valid_read_wstring(wcs);
requires valid_wstring_accept: valid_read_wstring(accept);
assigns \result \from wcs, indirect:wcs[0 .. ], indirect:accept[0 .. ];
ensures result_null_or_inside_wcs:
\result == \null || \subset (\result, wcs+(0 .. ));
...
...
@@ -155,16 +216,24 @@ extern wchar_t * wcsncpy(wchar_t *restrict dest, const wchar_t *restrict src, si
extern
wchar_t
*
wcspbrk
(
const
wchar_t
*
wcs
,
const
wchar_t
*
accept
);
/*@
assigns \result \from wcs, indirect:wcs[0 .. ], indirect:wc;
requires valid_wstring_wcs: valid_read_wstring(wcs);
assigns \result \from wcs, indirect:wcs[0 .. wcslen(wcs)], indirect:wc;
ensures result_null_or_inside_wcs:
\result == \null || \subset (\result, wcs+(0 .. ));
*/
extern
wchar_t
*
wcsrchr
(
const
wchar_t
*
wcs
,
wchar_t
wc
);
/*@ assigns \result \from indirect:wcs[0 .. ], indirect:accept[0 .. ]; */
/*@
requires valid_wstring_wcs: valid_read_wstring(wcs);
requires valid_wstring_accept: valid_read_wstring(accept);
assigns \result \from indirect:wcs[0 .. wcslen(wcs)],
indirect:accept[0 .. wcslen(accept)];
*/
extern
size_t
wcsspn
(
const
wchar_t
*
wcs
,
const
wchar_t
*
accept
);
/*@
requires valid_wstring_haystack: valid_read_wstring(haystack);
requires valid_wstring_needle: valid_read_wstring(needle);
assigns \result \from haystack, indirect:haystack[0 .. ], indirect:needle[0 .. ];
ensures result_null_or_inside_haystack:
\result == \null || \subset (\result, haystack+(0 .. ));
...
...
@@ -172,8 +241,9 @@ extern size_t wcsspn(const wchar_t *wcs, const wchar_t *accept);
extern
wchar_t
*
wcsstr
(
const
wchar_t
*
haystack
,
const
wchar_t
*
needle
);
/*@
requires room_nwstring: \valid(ws+(0..n-1));
requires valid_stream: \valid(stream);
assigns ws[0..n] \from indirect:n, indirect:*stream;
assigns ws[0..n
-1
] \from indirect:n, indirect:*stream;
assigns \result \from ws, indirect:n, indirect:*stream;
ensures result_null_or_same: \result == \null || \result == ws;
ensures terminated_string_on_success:
...
...
This diff is collapsed.
Click to expand it.
tests/libc/wchar_h.c
+
59
−
1
View file @
b337c046
#include
<stdio.h>
#include
<wchar.h>
volatile
int
v
;
int
main
()
{
FILE
*
fd
=
fopen
(
"bla"
,
"r"
);
if
(
!
fd
)
return
1
;
...
...
@@ -8,5 +8,63 @@ int main() {
wchar_t
*
res
=
fgetws
(
buf
,
29
,
fd
);
if
(
!
res
)
return
1
;
//@ assert res == buf;
wchar_t
buf2
[
2
];
buf2
[
0
]
=
L'a'
;
wchar_t
*
r
=
wmemchr
(
buf2
,
L'a'
,
2
);
// no warning
//@ check ok: r != \null;
r
=
wmemchr
(
0
,
0
,
0
);
// should be ok
//@ check ok: r == \null;
if
(
v
)
{
r
=
wmemchr
(
buf2
,
0
,
2
);
// red alarm (uninit)
//@ assert unreachable:\false;
}
r
=
wmemchr
(
buf2
,
L'a'
,
3
);
// no warning
//@ check ok: r != \null;
if
(
v
)
buf2
[
1
]
=
L'b'
;
r
=
wmemchr
(
buf2
,
L'a'
,
3
);
// no warning
//@ check ok: r != \null;
r
=
wmemchr
(
buf2
,
L'b'
,
3
);
// warning: buf2[1] maybe uninit
//@ check ok: r != \null;
buf2
[
1
]
=
L'b'
;
r
=
wmemchr
(
buf2
,
L'b'
,
3
);
// no warning
//@ check ok: r != \null;
wchar_t
*
wsrc
=
L"wide thing"
;
wchar_t
wdst
[
10
];
r
=
wcsncpy
(
wdst
,
wsrc
,
10
);
// no warning
//@ check ok: r == wdst;
//@ check ok: \initialized(&wdst[9]);
if
(
v
)
{
r
=
wcsncpy
(
wdst
,
wsrc
,
wcslen
(
wsrc
)
+
1
);
// error: not enough room
//@ assert unreachable:\false;
}
if
(
v
)
{
wcsncpy
(
wdst
,
wdst
,
10
);
// error: no separation
//@ assert unreachable:\false;
}
if
(
v
)
{
wcsncpy
(
0
,
wsrc
,
10
);
// error: invalid dest
//@ assert unreachable:\false;
}
if
(
v
)
{
wcsncpy
(
wdst
,
0
,
10
);
// error: invalid src
//@ assert unreachable:\false;
}
if
(
v
)
{
wcsncpy
(
wsrc
,
wdst
,
10
);
// error: non-writable dest
//@ assert unreachable:\false;
}
wcsncmp
(
wsrc
,
wsrc
,
11
);
// no warning
wcsncmp
(
wsrc
,
wdst
,
11
);
// warning: wdst possibly invalid
wchar_t
wdst2
[
20
]
=
{
0
};
wcsncat
(
wdst2
,
wsrc
,
11
);
// no warning
wcsncat
(
wdst2
,
wsrc
,
10
);
// no warning (if wdst2 is precise)
//@ loop unroll 10;
for
(
int
i
=
0
;
i
<
10
;
i
++
)
wdst2
[
i
]
=
L'A'
;
wdst2
[
10
]
=
L'\0'
;
// wdst2 now has length 10
if
(
v
)
{
wcsncat
(
wdst2
+
10
,
wdst2
,
10
);
// error: no separation
//@ assert unreachable:\false;
}
return
0
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment