Skip to content

Commit 1c68dd4

Browse files
authored
Merge pull request diffblue#1714 from tautschnig/c-library-strcat
C library: str(n)cat and upper-bound checks for mem{cpy,set,move}
2 parents 44b5bae + bb8cfaa commit 1c68dd4

File tree

6 files changed

+168
-47
lines changed

6 files changed

+168
-47
lines changed

regression/cbmc/memcpy1/main.c

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdint.h>
2+
#include <string.h>
3+
4+
int main()
5+
{
6+
uint8_t a;
7+
uint32_t b;
8+
9+
memcpy(&b, &a, sizeof(b));
10+
11+
return 0;
12+
}

regression/cbmc/memcpy1/test.desc

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--bounds-check --pointer-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
\[(__builtin___memcpy_chk|memcpy)\.pointer_dereference\.16\] dereference failure: pointer outside object bounds in \*\(\(\(const char \*\)src \+ \(signed long (long )?int\)n\) - \(signed long (long )?int\)1\): FAILURE$
8+
\*\* 1 of 17 failed
9+
--
10+
^warning: ignoring

regression/cbmc/memset3/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ main.c
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
77
\[.*] dereference failure: pointer outside dynamic object bounds in .*: FAILURE
8-
\*\* 1 of .* failed \(.*\)
8+
\*\* 2 of .* failed \(.*\)
99
--
1010
^warning: ignoring

regression/cbmc/strcat1/main.c

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <string.h>
2+
#include <assert.h>
3+
4+
int main()
5+
{
6+
char A1[5] = {'a', 'b', '\0'};
7+
char B1[3] = {'c', 'd', '\0'};
8+
9+
strcat(A1, B1);
10+
assert(A1[3] == 'd');
11+
assert(strlen(A1) == 4);
12+
13+
char A2[5] = {'a', 'b', '\0'};
14+
char B2[3] = {'c', 'd', '\0'};
15+
16+
strncat(A2, B2, 2);
17+
assert(A2[3] == 'd');
18+
assert(strlen(A2) == 4);
19+
20+
char A3[5] = {'a', 'b', '\0'};
21+
char B3[3] = {'c', 'd', '\0'};
22+
23+
strncat(A3, B3, 1);
24+
assert(A3[3] == '\0');
25+
assert(strlen(A3) == 4); // expected to fail
26+
27+
return 0;
28+
}

regression/cbmc/strcat1/test.desc

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--unwind 10
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
\[main.assertion.6\] assertion strlen\(A3\) == 4: FAILURE
8+
\*\* 1 of 8 failed
9+
--
10+
^warning: ignoring

src/ansi-c/library/string.c

+107-46
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,13 @@ __inline char *__builtin___strcat_chk(char *dst, const char *src, __CPROVER_size
5252
while(dst[i]!=0) i++;
5353

5454
__CPROVER_size_t j=0;
55-
char ch;
56-
do
55+
char ch = 1;
56+
for(; i < s && ch != (char)0; ++i, ++j)
5757
{
5858
ch=src[j];
5959
dst[i]=ch;
60-
i++;
61-
j++;
6260
}
63-
while(i<s && ch!=(char)0);
61+
dst[i] = '\0';
6462
#endif
6563
return dst;
6664
}
@@ -90,10 +88,19 @@ __inline char *__builtin___strncat_chk(
9088
#else
9189
__CPROVER_assert(__CPROVER_POINTER_OBJECT(dst)!=
9290
__CPROVER_POINTER_OBJECT(src), "strncat src/dst overlap");
93-
(void)*dst;
94-
(void)*src;
95-
(void)n;
96-
(void)s;
91+
92+
__CPROVER_size_t i = 0;
93+
while(dst[i] != 0)
94+
i++;
95+
96+
__CPROVER_size_t j = 0;
97+
char ch = 1;
98+
for(; i < s && j < n && ch != (char)0; ++i, ++j)
99+
{
100+
ch = src[j];
101+
dst[i] = ch;
102+
}
103+
dst[i] = '\0';
97104
#endif
98105
return dst;
99106
}
@@ -236,15 +243,13 @@ inline char *strcat(char *dst, const char *src)
236243
while(dst[i]!=0) i++;
237244

238245
__CPROVER_size_t j=0;
239-
char ch;
240-
do
246+
char ch = 1;
247+
for(; ch != (char)0; ++i, ++j)
241248
{
242249
ch=src[j];
243250
dst[i]=ch;
244-
i++;
245-
j++;
246251
}
247-
while(ch!=(char)0);
252+
dst[i] = '\0';
248253
#endif
249254
return dst;
250255
}
@@ -279,9 +284,19 @@ inline char *strncat(char *dst, const char *src, size_t n)
279284
#else
280285
__CPROVER_assert(__CPROVER_POINTER_OBJECT(dst)!=
281286
__CPROVER_POINTER_OBJECT(src), "strncat src/dst overlap");
282-
(void)*dst;
283-
(void)*src;
284-
(void)n;
287+
288+
__CPROVER_size_t i = 0;
289+
while(dst[i] != 0)
290+
i++;
291+
292+
__CPROVER_size_t j = 0;
293+
char ch = 1;
294+
for(; j < n && ch != (char)0; ++i, ++j)
295+
{
296+
ch = src[j];
297+
dst[i] = ch;
298+
}
299+
dst[i] = '\0';
285300
#endif
286301
return dst;
287302
}
@@ -533,10 +548,16 @@ void *memcpy(void *dst, const void *src, size_t n)
533548
__CPROVER_POINTER_OBJECT(src), "memcpy src/dst overlap");
534549
(void)*(char *)dst; // check that the memory is accessible
535550
(void)*(const char *)src; // check that the memory is accessible
536-
//for(__CPROVER_size_t i=0; i<n ; i++) ((char *)dst)[i]=((const char *)src)[i];
537-
char src_n[n];
538-
__CPROVER_array_copy(src_n, (char*)src);
539-
__CPROVER_array_replace((char*)dst, src_n);
551+
552+
if(n > 0)
553+
{
554+
(void)*(((char *)dst) + n - 1); // check that the memory is accessible
555+
(void)*(((const char *)src) + n - 1); // check that the memory is accessible
556+
//for(__CPROVER_size_t i=0; i<n ; i++) ((char *)dst)[i]=((const char *)src)[i];
557+
char src_n[n];
558+
__CPROVER_array_copy(src_n, (char *)src);
559+
__CPROVER_array_replace((char *)dst, src_n);
560+
}
540561
#endif
541562
return dst;
542563
}
@@ -566,10 +587,16 @@ void *__builtin___memcpy_chk(void *dst, const void *src, __CPROVER_size_t n, __C
566587
(void)*(char *)dst; // check that the memory is accessible
567588
(void)*(const char *)src; // check that the memory is accessible
568589
(void)size;
569-
//for(__CPROVER_size_t i=0; i<n ; i++) ((char *)dst)[i]=((const char *)src)[i];
570-
char src_n[n];
571-
__CPROVER_array_copy(src_n, (char*)src);
572-
__CPROVER_array_replace((char*)dst, src_n);
590+
591+
if(n > 0)
592+
{
593+
(void)*(((char *)dst) + n - 1); // check that the memory is accessible
594+
(void)*(((const char *)src) + n - 1); // check that the memory is accessible
595+
//for(__CPROVER_size_t i=0; i<n ; i++) ((char *)dst)[i]=((const char *)src)[i];
596+
char src_n[n];
597+
__CPROVER_array_copy(src_n, (char *)src);
598+
__CPROVER_array_replace((char *)dst, src_n);
599+
}
573600
#endif
574601
return dst;
575602
}
@@ -603,11 +630,16 @@ void *memset(void *s, int c, size_t n)
603630
__CPROVER_is_zero_string(s)=0;
604631
#else
605632
(void)*(char *)s; // check that the memory is accessible
606-
//char *sp=s;
607-
//for(__CPROVER_size_t i=0; i<n ; i++) sp[i]=c;
608-
unsigned char s_n[n];
609-
__CPROVER_array_set(s_n, (unsigned char)c);
610-
__CPROVER_array_replace((unsigned char*)s, s_n);
633+
634+
if(n > 0)
635+
{
636+
(void)*(((char *)s) + n - 1); // check that the memory is accessible
637+
//char *sp=s;
638+
//for(__CPROVER_size_t i=0; i<n ; i++) sp[i]=c;
639+
unsigned char s_n[n];
640+
__CPROVER_array_set(s_n, (unsigned char)c);
641+
__CPROVER_array_replace((unsigned char *)s, s_n);
642+
}
611643
#endif
612644
return s;
613645
}
@@ -631,13 +663,21 @@ void *__builtin_memset(void *s, int c, __CPROVER_size_t n)
631663
__CPROVER_zero_string_length(s)=0;
632664
}
633665
else
666+
{
634667
__CPROVER_is_zero_string(s)=0;
668+
}
635669
#else
636-
//char *sp=s;
637-
//for(__CPROVER_size_t i=0; i<n ; i++) sp[i]=c;
638-
unsigned char s_n[n];
639-
__CPROVER_array_set(s_n, (unsigned char)c);
640-
__CPROVER_array_replace((unsigned char*)s, s_n);
670+
(void)*(char *)s; // check that the memory is accessible
671+
672+
if(n > 0)
673+
{
674+
(void)*(((char *)s) + n - 1); // check that the memory is accessible
675+
//char *sp=s;
676+
//for(__CPROVER_size_t i=0; i<n ; i++) sp[i]=c;
677+
unsigned char s_n[n];
678+
__CPROVER_array_set(s_n, (unsigned char)c);
679+
__CPROVER_array_replace((unsigned char *)s, s_n);
680+
}
641681
#endif
642682
return s;
643683
}
@@ -666,11 +706,16 @@ void *__builtin___memset_chk(void *s, int c, __CPROVER_size_t n, __CPROVER_size_
666706
#else
667707
(void)*(char *)s; // check that the memory is accessible
668708
(void)size;
669-
//char *sp=s;
670-
//for(__CPROVER_size_t i=0; i<n ; i++) sp[i]=c;
671-
unsigned char s_n[n];
672-
__CPROVER_array_set(s_n, (unsigned char)c);
673-
__CPROVER_array_replace((unsigned char*)s, s_n);
709+
710+
if(n > 0)
711+
{
712+
(void)*(((char *)s) + n - 1); // check that the memory is accessible
713+
//char *sp=s;
714+
//for(__CPROVER_size_t i=0; i<n ; i++) sp[i]=c;
715+
unsigned char s_n[n];
716+
__CPROVER_array_set(s_n, (unsigned char)c);
717+
__CPROVER_array_replace((unsigned char *)s, s_n);
718+
}
674719
#endif
675720
return s;
676721
}
@@ -701,9 +746,15 @@ void *memmove(void *dest, const void *src, size_t n)
701746
#else
702747
(void)*(char *)dest; // check that the memory is accessible
703748
(void)*(const char *)src; // check that the memory is accessible
704-
char src_n[n];
705-
__CPROVER_array_copy(src_n, (char*)src);
706-
__CPROVER_array_replace((char*)dest, src_n);
749+
750+
if(n > 0)
751+
{
752+
(void)*(((char *)dest) + n - 1); // check that the memory is accessible
753+
(void)*(((const char *)src) + n - 1); // check that the memory is accessible
754+
char src_n[n];
755+
__CPROVER_array_copy(src_n, (char *)src);
756+
__CPROVER_array_replace((char *)dest, src_n);
757+
}
707758
#endif
708759
return dest;
709760
}
@@ -731,12 +782,22 @@ void *__builtin___memmove_chk(void *dest, const void *src, size_t n, __CPROVER_s
731782
__CPROVER_zero_string_length(dest)=__CPROVER_zero_string_length(src);
732783
}
733784
else
785+
{
734786
__CPROVER_is_zero_string(dest)=0;
787+
}
735788
#else
789+
(void)*(char *)dest; // check that the memory is accessible
790+
(void)*(const char *)src; // check that the memory is accessible
736791
(void)size;
737-
char src_n[n];
738-
__CPROVER_array_copy(src_n, (char*)src);
739-
__CPROVER_array_replace((char*)dest, src_n);
792+
793+
if(n > 0)
794+
{
795+
(void)*(((char *)dest) + n - 1); // check that the memory is accessible
796+
(void)*(((const char *)src) + n - 1); // check that the memory is accessible
797+
char src_n[n];
798+
__CPROVER_array_copy(src_n, (char *)src);
799+
__CPROVER_array_replace((char *)dest, src_n);
800+
}
740801
#endif
741802
return dest;
742803
}

0 commit comments

Comments
 (0)