I am currently recoding srtcat()
from the standard C library and I have set up some checks to avoid overlap problems. The problem is that my program still enters the error handling.
Here is the code:
char *my_strcat(char *restrict dest, const char *restrict src)
{
size_t dest_len = 0, src_len = 0;
char *p = dest;
src_len = my_strlen(src);
if (!dest || !src)
return NULL;
dest_len = my_strlen(dest);
if (src >= dest && src < dest dest_len) {
return NULL;
}
if (dest >= src && dest < src src_len) {
return NULL;
}
while (*p != '\0') p , dest_len ;
if (dest_len src_len 1 > sizeof(dest))
return NULL;
p = dest dest_len;
while (*src != '\0')
*p = *src ;
*p = '\0';
return dest;
}
size_t my_strlen(const char *s)
{
size_t count = 0;
if (s != NULL) {
while (*s != 0) {
count ;
s ;
}
}
return count;
}
I tested this way :
int main(int argc, char **argv)
{
const char *src = "Hello";
char dest[100] = " world!";
char *test = my_strcat(dest, src);
printf("Src : %s Dest : %s\n", src, dest);
printf("Return adress : %p, Value : %s\n", test, test);
return 0;
}
According to gdb
:
if (src >= dest && src < dest dest_len)
1: dest = 0x7fffffffda70 " world!"
2: src = 0x555555557004 "Hello"
3: dest_len = 0
4: src_len = 5
Output
Src : Hello Dest : world!
Return adress : (nil), Value : (null)
Do you see the problem?
Update
Following your suggestions I have modified the code like this:
char *my_strcat(char *restrict dest, const char *restrict src, size_t d_size)
{
size_t dest_len = 0, src_len = 0;
char *p = dest;
if (!dest || !src)
return NULL;
src_len = my_strlen(src);
dest_len = my_strlen(dest);
if (src >= dest && src < dest dest_len) {
return NULL;
}
if (dest >= src && dest < src src_len) {
return NULL;
}
while (*p != '\0') p , dest_len ;
if (dest_len src_len 1 > d_size)
return NULL;
p = dest dest_len;
while (*src != '\0')
*p = *src ;
*p = '\0';
return dest;
}
And in the main : char *test = my_strcat(dest, src, sizeof(dest));
But it still doesn't work :
Src : Hello Dest : world!
Return adress : 0x7fff74bc5650, Value : world!
CodePudding user response:
Having tried to guide toward understanding this problem, it seems best to present what should be working code (for study.) Sometimes too many words merely muddle the situation:
char *my_strcat(char *restrict dest, const char *restrict src, size_t d_size) {
if( !dest || !src )
return NULL;
size_t src_len = strlen( src );
size_t dest_len = strlen( dest );
if( dest_len src_len 1 > d_size )
return NULL;
char *p = dest dest_len;
while( (*p = *src ) != '\0' )
;
return dest;
}
int main() {
const char *src = "Hello";
char dest[100] = " world!";
printf("Src : %s Dest : %s\n", src, dest);
char *test = my_strcat( dest, src, sizeof dest );
if( test )
printf("Value : %s\n", test );
return 0;
}
Now, one can experiment by shrinking the size of dest
to something larger than " world!" but smaller than " world!Hello"... Perhaps 9 bytes???
And, now that the concatenation should be working (into a big enough buffer), adding the code to ensure there is no overlap of the actual character arrays. Known is the size of dest, and the length of src is measured.
CodePudding user response:
dest_len src_len 1 > sizeof(dest)
sizeof(dest)
is the size of the pointer sizeof(char*)
. If you want to check if the dest
will be overflowed, you have to pass the size as an argument. See strlcpy
or strncpy
.
src >= dest
Note that comparing pointers that do not point to the same array is technically invalid. To bring some breeze of validity, you can do (uintptr_t)stc >= (uintptr_t)dest
. How does pointer comparison work in C? Is it ok to compare pointers that don't point to the same array? Is comparing two pointers with < undefined behavior if they are both cast to an integer type? Why does comparing pointers with undefined behavior still give correct results? etc.