Skip to content

Commit f62d413

Browse files
committed
[libc++] Use builtins when redeclaring <string.h> functions
When we define the const-correct overloads of <string.h> functions in libc++ itself, use builtins whenever possible. This avoids depending on the presence of these functions in the C library headers. Also, as a fly-by, improve the tests for these functions since we basically didn't check anything but their signature. We could have used the wrong builtin (as long as the signature matched) without ever noticing, which was quite scary. Differential Revision: https://reviews.llvm.org/D138684
1 parent 07ca9cc commit f62d413

File tree

3 files changed

+262
-99
lines changed

3 files changed

+262
-99
lines changed

libcxx/include/string.h

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,41 +71,41 @@ size_t strlen(const char* s);
7171

7272
#if defined(__cplusplus) && !defined(_LIBCPP_STRING_H_HAS_CONST_OVERLOADS) && defined(_LIBCPP_PREFERRED_OVERLOAD)
7373
extern "C++" {
74-
inline _LIBCPP_INLINE_VISIBILITY
75-
char* __libcpp_strchr(const char* __s, int __c) {return (char*)strchr(__s, __c);}
76-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
77-
const char* strchr(const char* __s, int __c) {return __libcpp_strchr(__s, __c);}
78-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
79-
char* strchr( char* __s, int __c) {return __libcpp_strchr(__s, __c);}
80-
81-
inline _LIBCPP_INLINE_VISIBILITY
82-
char* __libcpp_strpbrk(const char* __s1, const char* __s2) {return (char*)strpbrk(__s1, __s2);}
83-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
84-
const char* strpbrk(const char* __s1, const char* __s2) {return __libcpp_strpbrk(__s1, __s2);}
85-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
86-
char* strpbrk( char* __s1, const char* __s2) {return __libcpp_strpbrk(__s1, __s2);}
87-
88-
inline _LIBCPP_INLINE_VISIBILITY
89-
char* __libcpp_strrchr(const char* __s, int __c) {return (char*)strrchr(__s, __c);}
90-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
91-
const char* strrchr(const char* __s, int __c) {return __libcpp_strrchr(__s, __c);}
92-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
93-
char* strrchr( char* __s, int __c) {return __libcpp_strrchr(__s, __c);}
94-
95-
inline _LIBCPP_INLINE_VISIBILITY
96-
void* __libcpp_memchr(const void* __s, int __c, size_t __n) {return (void*)memchr(__s, __c, __n);}
97-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
98-
const void* memchr(const void* __s, int __c, size_t __n) {return __libcpp_memchr(__s, __c, __n);}
99-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
100-
void* memchr( void* __s, int __c, size_t __n) {return __libcpp_memchr(__s, __c, __n);}
101-
102-
inline _LIBCPP_INLINE_VISIBILITY
103-
char* __libcpp_strstr(const char* __s1, const char* __s2) {return (char*)strstr(__s1, __s2);}
104-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
105-
const char* strstr(const char* __s1, const char* __s2) {return __libcpp_strstr(__s1, __s2);}
106-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
107-
char* strstr( char* __s1, const char* __s2) {return __libcpp_strstr(__s1, __s2);}
74+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const char* strchr(const char* __s, int __c) {
75+
return __builtin_strchr(__s, __c);
10876
}
77+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD char* strchr(char* __s, int __c) {
78+
return __builtin_strchr(__s, __c);
79+
}
80+
81+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const char* strpbrk(const char* __s1, const char* __s2) {
82+
return __builtin_strpbrk(__s1, __s2);
83+
}
84+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD char* strpbrk(char* __s1, const char* __s2) {
85+
return __builtin_strpbrk(__s1, __s2);
86+
}
87+
88+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const char* strrchr(const char* __s, int __c) {
89+
return __builtin_strrchr(__s, __c);
90+
}
91+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD char* strrchr(char* __s, int __c) {
92+
return __builtin_strrchr(__s, __c);
93+
}
94+
95+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const void* memchr(const void* __s, int __c, size_t __n) {
96+
return __builtin_memchr(__s, __c, __n);
97+
}
98+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD void* memchr(void* __s, int __c, size_t __n) {
99+
return __builtin_memchr(__s, __c, __n);
100+
}
101+
102+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD const char* strstr(const char* __s1, const char* __s2) {
103+
return __builtin_strstr(__s1, __s2);
104+
}
105+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD char* strstr(char* __s1, const char* __s2) {
106+
return __builtin_strstr(__s1, __s2);
107+
}
108+
} // extern "C++"
109109
#endif
110110

111111
#endif // _LIBCPP_STRING_H

libcxx/test/std/depr/depr.c.headers/string_h.pass.cpp

Lines changed: 114 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// <string.h>
1010

1111
#include <string.h>
12+
#include <cassert>
1213
#include <type_traits>
1314

1415
#include "test_macros.h"
@@ -19,38 +20,119 @@
1920

2021
int main(int, char**)
2122
{
22-
size_t s = 0;
23-
void* vp = 0;
24-
const void* vpc = 0;
25-
char* cp = 0;
26-
const char* cpc = 0;
27-
ASSERT_SAME_TYPE(void*, decltype(memcpy(vp, vpc, s)));
28-
ASSERT_SAME_TYPE(void*, decltype(memmove(vp, vpc, s)));
29-
ASSERT_SAME_TYPE(char*, decltype(strcpy(cp, cpc)));
30-
ASSERT_SAME_TYPE(char*, decltype(strncpy(cp, cpc, s)));
31-
ASSERT_SAME_TYPE(char*, decltype(strcat(cp, cpc)));
32-
ASSERT_SAME_TYPE(char*, decltype(strncat(cp, cpc, s)));
33-
ASSERT_SAME_TYPE(int, decltype(memcmp(vpc, vpc, s)));
34-
ASSERT_SAME_TYPE(int, decltype(strcmp(cpc, cpc)));
35-
ASSERT_SAME_TYPE(int, decltype(strncmp(cpc, cpc, s)));
36-
ASSERT_SAME_TYPE(int, decltype(strcoll(cpc, cpc)));
37-
ASSERT_SAME_TYPE(size_t, decltype(strxfrm(cp, cpc, s)));
38-
ASSERT_SAME_TYPE(void*, decltype(memchr(vp, 0, s)));
39-
ASSERT_SAME_TYPE(const void*, decltype(memchr(vpc, 0, s)));
40-
ASSERT_SAME_TYPE(char*, decltype(strchr(cp, 0)));
41-
ASSERT_SAME_TYPE(const char*, decltype(strchr(cpc, 0)));
42-
ASSERT_SAME_TYPE(size_t, decltype(strcspn(cpc, cpc)));
43-
ASSERT_SAME_TYPE(char*, decltype(strpbrk(cp, cpc)));
44-
ASSERT_SAME_TYPE(const char*, decltype(strpbrk(cpc, cpc)));
45-
ASSERT_SAME_TYPE(char*, decltype(strrchr(cp, 0)));
46-
ASSERT_SAME_TYPE(const char*, decltype(strrchr(cpc, 0)));
47-
ASSERT_SAME_TYPE(size_t, decltype(strspn(cpc, cpc)));
48-
ASSERT_SAME_TYPE(char*, decltype(strstr(cp, cpc)));
49-
ASSERT_SAME_TYPE(const char*, decltype(strstr(cpc, cpc)));
50-
ASSERT_SAME_TYPE(char*, decltype(strtok(cp, cpc)));
51-
ASSERT_SAME_TYPE(void*, decltype(memset(vp, 0, s)));
52-
ASSERT_SAME_TYPE(char*, decltype(strerror(0)));
53-
ASSERT_SAME_TYPE(size_t, decltype(strlen(cpc)));
23+
// Functions we get directly from the C library (just check the signature)
24+
{
25+
size_t s = 0;
26+
void* vp = 0;
27+
const void* vpc = 0;
28+
char* cp = 0;
29+
const char* cpc = 0;
30+
ASSERT_SAME_TYPE(void*, decltype(memcpy(vp, vpc, s)));
31+
ASSERT_SAME_TYPE(void*, decltype(memmove(vp, vpc, s)));
32+
ASSERT_SAME_TYPE(char*, decltype(strcpy(cp, cpc)));
33+
ASSERT_SAME_TYPE(char*, decltype(strncpy(cp, cpc, s)));
34+
ASSERT_SAME_TYPE(char*, decltype(strcat(cp, cpc)));
35+
ASSERT_SAME_TYPE(char*, decltype(strncat(cp, cpc, s)));
36+
ASSERT_SAME_TYPE(int, decltype(memcmp(vpc, vpc, s)));
37+
ASSERT_SAME_TYPE(int, decltype(strcmp(cpc, cpc)));
38+
ASSERT_SAME_TYPE(int, decltype(strncmp(cpc, cpc, s)));
39+
ASSERT_SAME_TYPE(int, decltype(strcoll(cpc, cpc)));
40+
ASSERT_SAME_TYPE(size_t, decltype(strxfrm(cp, cpc, s)));
41+
ASSERT_SAME_TYPE(size_t, decltype(strcspn(cpc, cpc)));
42+
ASSERT_SAME_TYPE(size_t, decltype(strspn(cpc, cpc)));
43+
ASSERT_SAME_TYPE(char*, decltype(strtok(cp, cpc)));
44+
ASSERT_SAME_TYPE(void*, decltype(memset(vp, 0, s)));
45+
ASSERT_SAME_TYPE(char*, decltype(strerror(0)));
46+
ASSERT_SAME_TYPE(size_t, decltype(strlen(cpc)));
47+
}
48+
49+
// Functions we (may) reimplement
50+
{
51+
// const char* strchr(const char*, int)
52+
char storage[] = "hello world";
53+
const char* s = storage;
54+
ASSERT_SAME_TYPE(const char*, decltype(strchr(s, 'l')));
55+
const char* res = strchr(s, 'l');
56+
assert(res == &s[2]);
57+
}
58+
{
59+
// char* strchr(char*, int)
60+
char storage[] = "hello world";
61+
char* s = storage;
62+
ASSERT_SAME_TYPE(char*, decltype(strchr(s, 'l')));
63+
char* res = strchr(s, 'l');
64+
assert(res == &s[2]);
65+
}
66+
67+
{
68+
// const char* strpbrk(const char*, const char*)
69+
char storage[] = "hello world";
70+
const char* s = storage;
71+
ASSERT_SAME_TYPE(const char*, decltype(strpbrk(s, "el")));
72+
const char* res = strpbrk(s, "el");
73+
assert(res == &s[1]);
74+
}
75+
{
76+
// char* strpbrk(char*, const char*)
77+
char storage[] = "hello world";
78+
char* s = storage;
79+
ASSERT_SAME_TYPE(char*, decltype(strpbrk(s, "el")));
80+
char* res = strpbrk(s, "el");
81+
assert(res == &s[1]);
82+
}
83+
84+
{
85+
// const char* strrchr(const char*, int)
86+
char storage[] = "hello world";
87+
const char* s = storage;
88+
ASSERT_SAME_TYPE(const char*, decltype(strrchr(s, 'l')));
89+
const char* res = strrchr(s, 'l');
90+
assert(res == &s[9]);
91+
}
92+
{
93+
// char* strrchr(char*, int)
94+
char storage[] = "hello world";
95+
char* s = storage;
96+
ASSERT_SAME_TYPE(char*, decltype(strrchr(s, 'l')));
97+
char* res = strrchr(s, 'l');
98+
assert(res == &s[9]);
99+
}
100+
101+
{
102+
// const void* memchr(const void*, int, size_t)
103+
char storage[] = "hello world";
104+
size_t count = 11;
105+
const void* s = storage;
106+
ASSERT_SAME_TYPE(const void*, decltype(memchr(s, 'l', count)));
107+
const void* res = memchr(s, 'l', count);
108+
assert(res == &storage[2]);
109+
}
110+
{
111+
// void* memchr(void*, int, size_t)
112+
char storage[] = "hello world";
113+
size_t count = 11;
114+
void* s = storage;
115+
ASSERT_SAME_TYPE(void*, decltype(memchr(s, 'l', count)));
116+
void* res = memchr(s, 'l', count);
117+
assert(res == &storage[2]);
118+
}
119+
120+
{
121+
// const char* strstr(const char*, const char*)
122+
char storage[] = "hello world";
123+
const char* s = storage;
124+
ASSERT_SAME_TYPE(const char*, decltype(strstr(s, "wor")));
125+
const char* res = strstr(s, "wor");
126+
assert(res == &storage[6]);
127+
}
128+
{
129+
// char* strstr(char*, const char*)
130+
char storage[] = "hello world";
131+
char* s = storage;
132+
ASSERT_SAME_TYPE(char*, decltype(strstr(s, "wor")));
133+
char* res = strstr(s, "wor");
134+
assert(res == &storage[6]);
135+
}
54136

55137
return 0;
56138
}

libcxx/test/std/strings/c.strings/cstring.pass.cpp

Lines changed: 114 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// <cstring>
1010

1111
#include <cstring>
12+
#include <cassert>
1213
#include <type_traits>
1314

1415
#include "test_macros.h"
@@ -19,39 +20,119 @@
1920

2021
int main(int, char**)
2122
{
22-
std::size_t s = 0;
23-
void* vp = 0;
24-
const void* vpc = 0;
25-
char* cp = 0;
26-
const char* cpc = 0;
27-
28-
ASSERT_SAME_TYPE(void*, decltype(std::memcpy(vp, vpc, s)));
29-
ASSERT_SAME_TYPE(void*, decltype(std::memmove(vp, vpc, s)));
30-
ASSERT_SAME_TYPE(char*, decltype(std::strcpy(cp, cpc)));
31-
ASSERT_SAME_TYPE(char*, decltype(std::strncpy(cp, cpc, s)));
32-
ASSERT_SAME_TYPE(char*, decltype(std::strcat(cp, cpc)));
33-
ASSERT_SAME_TYPE(char*, decltype(std::strncat(cp, cpc, s)));
34-
ASSERT_SAME_TYPE(int, decltype(std::memcmp(vpc, vpc, s)));
35-
ASSERT_SAME_TYPE(int, decltype(std::strcmp(cpc, cpc)));
36-
ASSERT_SAME_TYPE(int, decltype(std::strncmp(cpc, cpc, s)));
37-
ASSERT_SAME_TYPE(int, decltype(std::strcoll(cpc, cpc)));
38-
ASSERT_SAME_TYPE(std::size_t, decltype(std::strxfrm(cp, cpc, s)));
39-
ASSERT_SAME_TYPE(void*, decltype(std::memchr(vp, 0, s)));
40-
ASSERT_SAME_TYPE(const void*, decltype(std::memchr(vpc, 0, s)));
41-
ASSERT_SAME_TYPE(char*, decltype(std::strchr(cp, 0)));
42-
ASSERT_SAME_TYPE(const char*, decltype(std::strchr(cpc, 0)));
43-
ASSERT_SAME_TYPE(std::size_t, decltype(std::strcspn(cpc, cpc)));
44-
ASSERT_SAME_TYPE(char*, decltype(std::strpbrk(cp, cpc)));
45-
ASSERT_SAME_TYPE(const char*, decltype(std::strpbrk(cpc, cpc)));
46-
ASSERT_SAME_TYPE(char*, decltype(std::strrchr(cp, 0)));
47-
ASSERT_SAME_TYPE(const char*, decltype(std::strrchr(cpc, 0)));
48-
ASSERT_SAME_TYPE(std::size_t, decltype(std::strspn(cpc, cpc)));
49-
ASSERT_SAME_TYPE(char*, decltype(std::strstr(cp, cpc)));
50-
ASSERT_SAME_TYPE(const char*, decltype(std::strstr(cpc, cpc)));
51-
ASSERT_SAME_TYPE(char*, decltype(std::strtok(cp, cpc)));
52-
ASSERT_SAME_TYPE(void*, decltype(std::memset(vp, 0, s)));
53-
ASSERT_SAME_TYPE(char*, decltype(std::strerror(0)));
54-
ASSERT_SAME_TYPE(std::size_t, decltype(std::strlen(cpc)));
23+
// Functions we get directly from the C library (just check the signature)
24+
{
25+
std::size_t s = 0;
26+
void* vp = 0;
27+
const void* vpc = 0;
28+
char* cp = 0;
29+
const char* cpc = 0;
30+
ASSERT_SAME_TYPE(void*, decltype(std::memcpy(vp, vpc, s)));
31+
ASSERT_SAME_TYPE(void*, decltype(std::memmove(vp, vpc, s)));
32+
ASSERT_SAME_TYPE(char*, decltype(std::strcpy(cp, cpc)));
33+
ASSERT_SAME_TYPE(char*, decltype(std::strncpy(cp, cpc, s)));
34+
ASSERT_SAME_TYPE(char*, decltype(std::strcat(cp, cpc)));
35+
ASSERT_SAME_TYPE(char*, decltype(std::strncat(cp, cpc, s)));
36+
ASSERT_SAME_TYPE(int, decltype(std::memcmp(vpc, vpc, s)));
37+
ASSERT_SAME_TYPE(int, decltype(std::strcmp(cpc, cpc)));
38+
ASSERT_SAME_TYPE(int, decltype(std::strncmp(cpc, cpc, s)));
39+
ASSERT_SAME_TYPE(int, decltype(std::strcoll(cpc, cpc)));
40+
ASSERT_SAME_TYPE(std::size_t, decltype(std::strxfrm(cp, cpc, s)));
41+
ASSERT_SAME_TYPE(std::size_t, decltype(std::strcspn(cpc, cpc)));
42+
ASSERT_SAME_TYPE(std::size_t, decltype(std::strspn(cpc, cpc)));
43+
ASSERT_SAME_TYPE(char*, decltype(std::strtok(cp, cpc)));
44+
ASSERT_SAME_TYPE(void*, decltype(std::memset(vp, 0, s)));
45+
ASSERT_SAME_TYPE(char*, decltype(std::strerror(0)));
46+
ASSERT_SAME_TYPE(std::size_t, decltype(std::strlen(cpc)));
47+
}
48+
49+
// Functions we (may) reimplement
50+
{
51+
// const char* strchr(const char*, int)
52+
char storage[] = "hello world";
53+
const char* s = storage;
54+
ASSERT_SAME_TYPE(const char*, decltype(std::strchr(s, 'l')));
55+
const char* res = std::strchr(s, 'l');
56+
assert(res == &s[2]);
57+
}
58+
{
59+
// char* strchr(char*, int)
60+
char storage[] = "hello world";
61+
char* s = storage;
62+
ASSERT_SAME_TYPE(char*, decltype(std::strchr(s, 'l')));
63+
char* res = std::strchr(s, 'l');
64+
assert(res == &s[2]);
65+
}
66+
67+
{
68+
// const char* strpbrk(const char*, const char*)
69+
char storage[] = "hello world";
70+
const char* s = storage;
71+
ASSERT_SAME_TYPE(const char*, decltype(std::strpbrk(s, "el")));
72+
const char* res = std::strpbrk(s, "el");
73+
assert(res == &s[1]);
74+
}
75+
{
76+
// char* strpbrk(char*, const char*)
77+
char storage[] = "hello world";
78+
char* s = storage;
79+
ASSERT_SAME_TYPE(char*, decltype(std::strpbrk(s, "el")));
80+
char* res = std::strpbrk(s, "el");
81+
assert(res == &s[1]);
82+
}
83+
84+
{
85+
// const char* strrchr(const char*, int)
86+
char storage[] = "hello world";
87+
const char* s = storage;
88+
ASSERT_SAME_TYPE(const char*, decltype(std::strrchr(s, 'l')));
89+
const char* res = std::strrchr(s, 'l');
90+
assert(res == &s[9]);
91+
}
92+
{
93+
// char* strrchr(char*, int)
94+
char storage[] = "hello world";
95+
char* s = storage;
96+
ASSERT_SAME_TYPE(char*, decltype(std::strrchr(s, 'l')));
97+
char* res = std::strrchr(s, 'l');
98+
assert(res == &s[9]);
99+
}
100+
101+
{
102+
// const void* memchr(const void*, int, size_t)
103+
char storage[] = "hello world";
104+
std::size_t count = 11;
105+
const void* s = storage;
106+
ASSERT_SAME_TYPE(const void*, decltype(std::memchr(s, 'l', count)));
107+
const void* res = std::memchr(s, 'l', count);
108+
assert(res == &storage[2]);
109+
}
110+
{
111+
// void* memchr(void*, int, size_t)
112+
char storage[] = "hello world";
113+
std::size_t count = 11;
114+
void* s = storage;
115+
ASSERT_SAME_TYPE(void*, decltype(std::memchr(s, 'l', count)));
116+
void* res = std::memchr(s, 'l', count);
117+
assert(res == &storage[2]);
118+
}
119+
120+
{
121+
// const char* strstr(const char*, const char*)
122+
char storage[] = "hello world";
123+
const char* s = storage;
124+
ASSERT_SAME_TYPE(const char*, decltype(std::strstr(s, "wor")));
125+
const char* res = std::strstr(s, "wor");
126+
assert(res == &storage[6]);
127+
}
128+
{
129+
// char* strstr(char*, const char*)
130+
char storage[] = "hello world";
131+
char* s = storage;
132+
ASSERT_SAME_TYPE(char*, decltype(std::strstr(s, "wor")));
133+
char* res = std::strstr(s, "wor");
134+
assert(res == &storage[6]);
135+
}
55136

56137
return 0;
57138
}

0 commit comments

Comments
 (0)