Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
Iam trying to reproduce the behaviour of strlcat in C,writing my own function.
I need to append string1 to the end of string2.
I start looping through string1 until it finds a '\0', and then I try to write string2 to string1 from there. However I think this is not the way to do it because it throw some segmentation fault and maybe Im acessing memor I shouldn't (?).
char *ft_srlcat(char *dst, char *src, int size) {
int i;
int j;
i = 0;
j = 0;
while (dst[i] != '\0')
{
i++;
}
while (size > 0 || src[j] != '\0')
{
dst[i] = src[j];
i++;
j++;
size--;
}
printf("%s\n", dst);
}
void main {
ft_strlcat("A very long", "teste to see if it works"), 5
}
Use the correct type for sizes (size_t)
size to make any sense should indicate the dst array length
You cant call this function if dst is not modifiable (const array for example)
When you define function as returning something - return it.
Your function is not null terminating the string if the array is not big enough to accommodate both strings
char *ft_srlcat(char *dst, char *src, size_t size)
{
char *wrk = size ? dst : NULL;
if(dst && src)
{
while (*dst && size) {dst++; size--;}
while (size > 1 && (*dst++ = *src++)) size--;
if(!size && !*dst) *dst = 0;
}
return wrk;
}
int main(void)
{
char dest[15] = "Hello world.";
char dest2[5] = "Hello world.";
char dest1[128] = "Hello world.";
char dest3[0] = "Hello world.";
printf("`%s`\n", ft_srlcat(dest, "Goodbye", sizeof(dest)));
printf("`%s`\n", ft_srlcat(dest2, "Goodbye", sizeof(dest2)));
printf("`%s`\n", ft_srlcat(dest1, "Goodbye", sizeof(dest1)));
printf("`%s`\n", ft_srlcat(dest3, "Goodbye", sizeof(dest3)) ? dest3 : "NULL");
printf("`%s`\n", ft_srlcat(dest1, NULL, sizeof(dest3)) ? dest3 : "NULL");
printf("`%s`\n", ft_srlcat(NULL, "Goodbye", sizeof(dest3)) ? dest3 : "NULL");
printf("`%s`\n", ft_srlcat("Hello world.", "Goodbye", sizeof("Hello world.")));
}
https://godbolt.org/z/6xGafsjjo
Related
I am fairly new to C-coding and I have a task where we run libFuzzer on a basic C-program to exploit problems and fix them. This is my C-program (it takes a string input and changes "&" to "&", ">" to ">" and "<" to "<"):
char *checkString(char str[50]) {
int i;
char *newstr;
newstr = (char *)malloc(200);
for (i = 0; i < strlen(str); i++) {
if (str[i] == '&') {
const char *ch = "&";
strncat(newstr, ch, 4);
} else if (str[i] == '<') {
const char *ch = "<";
strncat(newstr, ch, 3);
} else if (str[i] == '>') {
const char *ch = ">";
strncat(newstr, ch, 3);
} else {
const char ch = str[i];
strncat(newstr, &ch, 1);
}
}
return newstr;
}
This is the error message from libFuzzer:
SUMMARY: AddressSanitizer: heap-buffer-overflow (/path/to/a.out+0x50dc14) in strncat
Anybody who knows how to possibly fix this heap buffer overflow problem? Thanks!
After newstr = (char *)malloc(200);, newstr is not yet properly initialized so you must not call strncat( newstr, ... ).
You can solve that e.g. by calling strcpy( newstr, "" ); after malloc() or by replacing malloc(200) with calloc(200,1) which fills the entire buffer with NUL.
Besides, as #stevesummit has mentioned, despite its declaration there is no guarantee, that strlen(str) < 50. So instead of allocating a fix number of 200 characters, you should alloc strlen(str)*4 + 1
... or strlen(str)*5 + 1 if what you're doing is HTML esacping and you realize that & should be replaced by &
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am using C90, and I want to read a string that looks something like this:
str = " INFO INFO INFO INFO"
INFO is a word without white spaces in it.
I want to know, what is the best way to read the first INFO word?
The problem is that there could be any number (up to 166) of whitespace characters before the INFO, but a white space character is also what marks the end of the INFO word. So I need to ignore the whitespaces before it, but stop reading at a white space after it.
Is there a function that can do it? Or do I need to write it myself?
And if I write it myself, do I actually need an if statement that looks like "character != '\t' && character != " " && character != ...."?
or there is a way to tell the language x == whitespace?
what is the best way to read the first INFO word?
is there a function that can do it?
Funny enough there is.
char info1[20]; // some constant size buffer
if (sscanf(str, "%19s", info1) != 1) {
/* handle error */
}
do I actually need an if statemant that looks like "character != '\t' && character != " " && character != ...." ?
There is strchr and strspn functions. You could just:
const char * const whitespace = " \f\n\r\t\v";
const char * const first_word = str + strspn(str, whitespace);
const size_t len_of_first_word = strcspn(first_word, whitespace);
printf("%.*s", (int)len_of_first_word, first_word);
// TODO: add error checking.
When you learn is good to write it yourself even in the simplest form. Here you have an example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *mystrchr(const char *str, char ch)
{
if(str)
{
while(*str)
{
if(*str == ch) break;
str++;
}
}
return (str && *str) ? (char *)str : NULL;
}
void freetok(char **argv, size_t size)
{
if(argv)
{
for(size_t token = 0; token < size; token++)
{
free(argv[token]);
}
free(argv);
}
}
char **mytok(const char *src, size_t *argc, const char *separators)
{
char **argv = NULL;
char **tmp;
const char *tokenstart;
*argc = 0;
if(src)
{
do
{
while(mystrchr(separators, *src)) src++;
if(*src)
{
tmp = realloc(argv, (*argc + 1) * sizeof(argv));
if(!tmp)
{
goto cleanup;
}
argv = tmp;
tokenstart = src;
while(*src && !mystrchr(separators, *src)) src++;
argv[*argc] = malloc(src - tokenstart + 1);
if(!argv[*argc])
{
goto cleanup;
}
memcpy(argv[*argc], tokenstart, src - tokenstart);
argv[(*argc)++][src - tokenstart] = 0;
}
}while(*src);
}
return argv;
cleanup:
freetok(argv, *argc);
*argc = (ssize_t)-1;
return NULL;
}
int main(void)
{
char *x = " INFO ,, INFO1 INFO2 INFO3 ";
size_t ntokens;
char **tokens = mytok(x, &ntokens, " ,");
for(size_t token = 0; token < ntokens; token++)
printf("token np %2zu = \"%s\"\n", token, tokens[token]);
freetok(tokens, ntokens);
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Can someone please explain to me why using malloc here causes a seg fault at the specified line in mystrncat()? I was under the impression that I had access to elements of the heap across different stack frames. Is there any material I can look at to better understand this topic?
Thank You.
EDIT:
Here is my updated code, still segfault at the location.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define initial_malloc 20
char* mystrncat(char *dest, char *source, int n);
int main(void) {
char *str1 = malloc(initial_malloc);
char *str2 = malloc(initial_malloc);
memset(str1, '\0', 20);
memset(str2, '\0', 20);
str1 = "hello";
str2 = "World";
mystrncat(str1, str2, 3);
return EXIT_SUCCESS;
}
char *mystrncat(char *dest, char *source, int n) {
int i, j, k, l;
j = strlen(dest);
for (i = 0; i < n && source[i] != '\0'; i++)
;
for (k = j, l = 0; k < (j + i - 1); k++, l++) {
dest[k] = source[l]; /* <-------runtime error here with malloc */
}
dest[k] = '\0';
return dest;
}
= does not copy the string. It only assigns the poiner with the address (in your case) of the string literal. String literals are read only and any attempt of writing them usually ends in the SEGFAULT.
You need to copy (using the strcpy) the literal to the str1 and then you can concat them.
Second string (str2) is not needed at all here.
Use proper types (size_t) and try to be const correct
BTW your malloced memory here is lost.
A bit amended version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define initial_malloc 20
char* mystrncat(char *, const char *, size_t);
int main(void) {
char *str1 = malloc(initial_malloc);
if(str1)
{
strcpy(str1, "hello");
mystrncat(str1, "World", 3);
printf("%s\n", str1);
free(str1);
}
return EXIT_SUCCESS;
}
char *mystrncat(char *dest, const char *src, size_t n)
{
char *SavedDest = dest;
while(*dest++);
dest--;
while(n && *src)
{
*dest++ = *src++;
n--;
}
*dest = 0;
return SavedDest;
}
You change str1 and str2 just before you invoke mystrncat and make them point to string literals. Attempting to modify the memory pointed to by str1 has undefined behavior, in your case a segmentation fault.
Since you intend to initialize the allocated memory, use calloc() that will perform the initialization more efficiently and with the correct size. Your code does not use initial_malloc, so it will likely fail if initial_malloc is redefined to a different value.
You should output the resulting string to check for correctness.
Note also that your function mystrncat has different semantics from the standard function strncat. If this is your intent, the name mystrncat is misleading.
Here is a modified version with the standard semantics:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define initial_malloc 20
char *mystrncat(char *dest, const char *source, size_t n);
int main(void) {
char *str1 = malloc(initial_malloc);
char *str2 = malloc(initial_malloc);
if (str1 == NULL || str2 == NULL) {
printf("memory allocation failure\n");
return EXIT_FAILURE;
}
strcpy(str1, "hello");
strcpy(str2, "World");
mystrncat(str1, str2, 3);
printf("%s\n", str1);
free(str1);
free(str2);
return EXIT_SUCCESS;
}
char *mystrncat(char *dest, const char *source, size_t n) {
size_t i, j;
for (i = 0, j = strlen(dest); i < n && source[i]; i++, j++) {
dest[j] = source[i];
}
dest[j] = '\0';
return dest;
}
I'm trying to concatenate two strings using pointer in C, but it doesn't work 100%. At the end of the output String, many unknown characters appear...
char* concat_string (char* s1, char* s2) {
char *s;
int k=0;
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
while (*s1!='\0') {
*(s+k)=*s1;
k++;
s1++;
}
while (*s2!='\0') {
*(s+k)=*s2;
k++;
s2++;
}
return s;
}
int main () {
char *ch1, *ch2, *s;
char cch1[10], cch2[10];
printf("ch1 ? ");
scanf("%s",cch1);
printf("ch2 ? ");
scanf("%s",cch2);
ch1=cch1;
ch2=cch2;
s=concat_string(ch1, ch2);
printf("\n%s + %s = ", ch1, ch2);
while (*s!='\0') {
printf("%c", *s);
s++;
}
}
You're not including space for the terminator in the concatenated result. This:
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
should be:
s = malloc(strlen(s1) + strlen(s2) + 1);
You're not copying the terminator either, which explains the result you're seeing.
Also, don't cast malloc()'s return value in C, and make your input strings const.
Your code is very hard to read. The use of an integer indexing variable instead of just using pointers makes it needlessly complicated. For reference, here's how I would write it:
char * concat_string(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) + 1);
if(s != NULL)
{
char *p = s;
while((*p++ = *s1++) != '\0');
--p;
while((*p++ = *s2++) != '\0');
}
return s;
}
This is of course still somewhat terse, but I'd argue it's more readable than your version.
printf expects null terminated strings. Otherwise, it will print whatever characters in memory until it hits one. Your concat_string function doesn't put a null terminator on the string.
char* concat_string (char* s1, char* s2){char *s;int k=0;
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
while(*s1!='\0'){*(s+k)=*s1;k++;s1++; }
while(*s2!='\0'){*(s+k)=*s2;k++;s2++;}
*(s+k) = 0;
return s;
}
Also, this function is already written for you, just try using strcat.
#include<stdio.h>
char* my_strcpy(char*,const char*);
int main(){
char a[20];
char* s = "Hello world!";
char* d = a;
my_strcpy(d,s);
printf("\n d : %s \n",d);
return 0;
}
char* my_strcpy(char* dest,const char* sour){
if(NULL == dest || NULL == sour){
return NULL;
}
while(1){
*dest++ = *sour++;
if(*sour == '\0'){
*dest = *sour;
break;
}
}
}
why do we need the char* as a return type for my_strcpy. If the d is " " it gives me a segmentation fault. If I assign it with a it works fine. Why does it give seg fault when given "".
MODIFIED : After the answers
#include<stdio.h>
char* my_strcpy(char*,const char*);
int main(){
char* ret;
char a[20];
char* s = "Hello world!";
char* d = "";
ret = my_strcpy(d,s);
if(NULL == ret){
perror("\nret");
}
// printf("\n d : %s \n",d);
return 0;
}
char* my_strcpy(char* dest,const char* sour){
char* temp;
if(NULL == dest || NULL == sour){
return NULL;
}
temp = dest;
while(1){
*temp++ = *sour++;
if(*sour == '\0'){
*temp = *sour;
break;
}
}
return temp;
}
This still gives a segfault. How to handle the condition if s="" when passed to the function strcpy.
You asked: "If the d is " " it gives me a segmentation fault."
Answer:
If you assign "" or " " to d, there will not be enough space to fit "Hello World". Moreover, a constant string if assigned to a memory page tagged as data might not allow modification.
You asked "why do we need the char* as a return type for my_strcpy" as the original strcpy I presume.
Answer:
You do not have to. You could have void as return type. However, it makes it practical if one is to do something like this:
printf ("%s", strcpy (dest, sour));
Corrected code:
while(1){
*dest++ = *sour++;
if(*(sour-1) == '\0'){
break;
}
or better:
while(*sour != '\0'){
*dest++ = *sour++;
}
*dest = *sour;
Here you:
Assign the value at *sour to *dest
Increment both sour and dest so now the point to the next characters
Test if *dest is now NUL to exit the loop
As you can see, the 3rd step reads from uninitialized memory. You should test if the value that was assigned before incrementing was NUL.
*dest++ = *sour++;
if(*dest == '\0'){
break;
}
If the dest you pass in is a constant string like " " you get a segfault because string constants are stored in read-only memory. They cannot be modified.
Correct:
if(*dest == '\0'){
should be:
if(*(dest - 1) == '\0'){
Note:
*dest++ = *sour++;
is equivalent to
*dest = *sour;
sour++;
dest++;
You increments dest after assignment, and so you are checking \0 at position where garbage value present as you don't initialize a[] -causes Undefined behaviour. Additionally you don't return after while loop.
You can simply write your function as:
char* my_strcpy(char* dest,const char* sour){
if(NULL == dest || NULL == sour)
return NULL;
char* d = dest;
while(*dest++ = *sour++)
;
return d;
}
Give it a try!!
here is a simple version:
char *my_strcpy(char *d, const char *s){
int i=0;
while(d[i++]=*s++)
/*done inside condition*/;
return d;
}
I would advise to implement strcpy as:
char* my_strcpy (char* s1, const char* s2)
{
char* return_val = s1;
*s1 = *s2;
while(*s2 != '\0')
{
s1++;
s2++;
*s1 = *s2;
}
return return_val;
}
Always avoid multiple ++ statements in the same expression. There is never a reason to do so and it will sooner or later give you a handful of undefined/unspecified behavior bugs.