Passing char to function breaks heap - c

Psudo code below, but does anyone have any idea why this would be breaking the heap? The urlencode function is a standard library function downloaded elsewhere, and appears to function as designed. In the actual code I'm using dynamic size char arrays, thus the reason for the malloc requirement in main.
/* Returns a url-encoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
char *urlencode(char *str) {
//char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
while (*pstr) {
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
*pbuf++ = *pstr;
else if (*pstr == ' ')
*pbuf++ = '+';
else
*pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
pstr++;
}
*pbuf = '\0';
return buf;
}
int testFunction(char *str) {
char *tmpstr;
tmpstr = urlencode(str);
// Now we do a bunch of stuff
// that doesn't use str
free(tmpstr);
return 0;
// At the end of the function,
// the debugger shows str equal
// to "This is a test"
}
int main() {
char *str = NULL;
str = malloc(100);
strcpy(str, "This is a test");
testFunction(str);
free(str); // Debugger shows correct value for str, but "free" breaks the heap
return 0;
}
Thanks.

I would guess that str was already freed by free(tmpstr); - please have a look at the behavior of the urlencode-function. It seems like it does not generate a new string as return value, but passes the (changed) input string back.

the problem turned out to be an issue with the size calculation for the initial malloc of str being executed as 0. Thank you for the comments, unfortunately no way to really mark an answer as comments.
If this is an improper way to close this out, please let me know.

Related

How can I solve heap-buffer-overflow in my C-code?

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 "&amp", ">" to "&gt" and "<" to "&lt"):
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 = "&amp";
strncat(newstr, ch, 4);
} else if (str[i] == '<') {
const char *ch = "&lt";
strncat(newstr, ch, 3);
} else if (str[i] == '>') {
const char *ch = "&gt";
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 &

Concatenate two strings without using strcat

I wrote a function to concatenate two strings (s = "computer"; t = "keyboard"), but my code only returns "keyboard". Please point out the mistakes.
char *concat(char *s, char *t) {
s = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = s;
while (*p != '\0') {
++p;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return s;
}
I do not want to use strcat(). This is a test program from Stepik, so I cannot change anything in the main function.
Here is the question: Write a function which receives two character pointers and returns a new character pointer representing their concatenation.
char *myconcat(const char *s1, const char *s2)
{
size_t len1,len2;
char *result = malloc((len1 = strlen(s1)) + (len2 = strlen(s2)) + 1);
if(result)
{
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
}
return result;
}
You have s="computer" when passed into a function, and then on the very first line you reassign it with malloc, so "computer" is gone.
You can debug your program step by step, or just print the values to the console. This will help you to find the error.
You are on the right track:
you allocate the correct amount of memory,
you copy the second string correctly,
you set the null terminator correctly,
you return the pointer to the allocated block.
Yet there are some issues:
you overwrite the pointer to the first string with that returned by malloc(),
you read from the allocated memory block instead of copying the first string: this has undefined behavior,
(minor) the argument strings should be declared as const char * as you do not modify these strings.
Here is a corrected version:
#include <stdlib.h>
#include <string.h>
char *concat(const char *s, const char *t) {
char *ret = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = ret;
while (*s != '\0') {
*p++ = *s++;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return ret;
}

How to create a new char* in standard C

I have this code made for C++ (it works):
char* ConcatCharToCharArray(char *Str, char Chr)
{
char *StrResult = new char[strlen(Str) + 2];
strcpy(StrResult, Str);
StrResult[strlen(Str)] = Chr;
StrResult[strlen(Str) + 1] = '\0';
return StrResult;
}
/* Example: String = "Hello worl"
Char = "d"
Final string = "Hello world" */
The little problem is that I'm making a standard C program in Ubuntu and I need this code.
And "new" is NOT being recognized as a reserved word and there's even a red mark under it.
I tried: char *StrResult[strlen(Str) + 2], but it doesn't work because that way only admits constant values. I'm guessing "malloc" would be the standard C solution in here, how could I do this with "malloc" or any other way for that matter? Thank you so much.
new is the C++ way of allocating memory. In C you're right, you need to use malloc.
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t len = strlen( Str );
char *StrResult = malloc( len + 2 );
/* Check for StrResult==NULL here */
strcpy(StrResult, Str);
StrResult[len] = Chr;
StrResult[len+1] = '\0';
return StrResult;
}
When you're done with the memory, you'd call free( StrResult ).
Yes, you need malloc and you are confusing C with C++ here (since new comes from C++):
char *StrResult = (*char) malloc((strlen(Str) + 2) * sizeof(char));
char takes only one byte (see this question), so you don't need to multiply by it's size:
char *StrResult = (*char) malloc(strlen(Str) + 2);
One way:
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t StrLen = strlen(Str);
char *StrResult = malloc(StrLen + 2);
if(NULL == StrResult)
goto CLEANUP;
strcpy(StrResult, Str);
StrResult[StrLen++] = Chr;
StrResult[StrLen] = '\0';
CLEANUP:
return StrResult;
}
However, the above allocates a new string, instead of concatenating a character to an existing string. Here is a way to expand an existing string with an additional character:
int StrConcatChar(char **string, char character)
{
int rCode=0;
size_t stringLen;
char *temp;
if(NULL == string)
{
rCode=EINVAL;
goto CLEANUP;
}
stringLen = *string ? strlen(*string) : 0;
errno=0;
temp=realloc(*string, stringLen+2);
if(NULL == temp)
{
rCode=errno?errno:ENOMEM;
goto CLEANUP;
}
*string=temp;
(*string)[stringLen++] = character;
(*string)[stringLen] = '\0';
CLEANUP:
return(rCode);
}
The above function might be called like this:
{
int rCode=0;
char *buffer=NULL;
buffer=strdup("Hello worl");
if(NULL == buffer)
/* handle error condition */
rCode=StrConcatChar(&buffer, 'd');
if(rCode)
/* handle error condition */
...
if(buffer)
free(buffer);
}

Remove first char of string C

Im trying to remove the first char of the string and keep the remainder, my current code doesnt compile and im confused on how to fix it.
My code:
char * newStr (char * charBuffer)
{
int len = strlen(charBuffer);
int i = 1;
char v;
if(charBuffer[0] == 'A' || charBuffer[0] == 'Q'){
for(i=1;i<len;i++)
v = v + charBuffer[i];
}
v = v + '\0';
return v;
}
Gcc: "Warning: return makes pointer from integer without a cast"
Also: "char * newStr (char * charBuffer)" needs to remain the same.
Strings don't work like this in C. You're summing up all of the characters in the buffer into the v variable. You can't use + to concatenate. The code you posted has some serious problems which indicate that there's an understanding gap with how to use C.
Try this:
char *newStr (char *charBuffer) {
int length = strlen(charBuffer);
char *str;
if (length <= 1) {
str = (char *) malloc(1);
str[0] = '\0';
} else {
str = (char *) malloc(length);
strcpy(str, &charBuffer[1]);
}
return str;
}
or this:
char *newStr (char *charBuffer) {
char *str;
if (strlen(charBuffer) == 0)
str = charBuffer;
else
str = charBuffer + 1;
return str;
}
Depending on whether you want to allocate a new string or not. You'll also have to add the code for handling the cases that don't start with 'Q' or 'A'. I didn't include those because I'm not sure exactly what you're trying to do here.
Make sure you do some research into allocating and deallocating memory with malloc and free. These are fundamental functions to be able to use if you're going to be doing C programming.
Well, your description says you want to deal with "strings", but you code deals with char buffers/pointers. The simplest approach to remove the first character for strings would be
const char *newStr(const char *string)
{
return string+1;
}
but as that doesn't look at all like what your code is doing, you probabaly want something different. For example, if you want to just remove a leading 'A' or 'Q' and then copy the string to a buffer, you want something like
char *newStr(const char *string)
{
if (string[0] == 'A' || string[0] == 'Q')
string++;
return strdup(string);
}
You can simply move your char pointer one character in:
char* newstring = oldstring + 1;
Your function is declared to return a char * and you are returning a char.
Furthermore, why don't you just return a pointer to the second character?
char * newStr (char * charBuffer)
{
if (charBuffer && (*charBuffer == 'A' || *charBuffer == 'Q')) return charBuffer + 1;
return charBuffer;
}
Several of the other answers recommended returning charBuffer + 1. As I noted in my previous comment:
This is bad practice. What if the string is dynamically allocated? Perhaps eventually the storage will be freed (starting from the second character). The string should be copied to new storage first.
Freeing a piece of storage from the middle will result in undefined behavior.
Instead, try the strdup function which will return a duplicate of the given string.
#include <string.h>
#include <stdio.h>
char *newStr(char* charBuffer) {
if (charBuffer && (charBuffer[0] == 'A' || charBuffer[0] == 'Q'))
return strdup(charBuffer + 1);
else
return strdup(charBuffer);
}
void main() {
char a[7] = "Advait";
char b[5] = "John";
printf("%s\n",newStr(a)); // Prints "dvait"
printf("%s\n",newStr(b)); // Prints "John"
}

extract string value from a string

gcc 4.4.3
c89
I have the following string
sip:12387654345443222118765#xxx.xxx.xxx.xxx
How can I extract just the number? I just want the number.
12387654345443222118765
Many thanks for any advice,
There are lots of ways to do it, if the string is well-formatted you could use strchr() to search for the : and use strchr() again to search for the # and take everything in between.
Here is another method that looks for a continuous sequence of digits:
char *start = sipStr + strcspn(sipStr, "0123456789");
int len = strspn(start, "0123456789");
char *copy = malloc(len + 1);
memcpy(copy, start, len);
copy[len] = '\0'; //add null terminator
...
//don't forget to
free(copy);
It sounds like you want it as a numeric type, which is going to be difficult (it's too large to fit in an int or a long). In theory you could just do:
const char* original = "sip:12387654345443222118765#xxx.xxx.xxx.xxx";
long num = strtoul(original + 4, NULL, 10);
but it will overflow and strtoul will return -1. If you want it as a string and you know it's always going to be that exact length, you can just pull out the substring with strcpy/strncpy:
const char* original = "sip:12387654345443222118765#xxx.xxx.xxx.xxx";
char num[24];
strncpy(num, original + 4, 23);
num[23] = 0;
If you don't know it's going to be 23 characters long every time, you'll need to find the # sign in the original string first:
unsigned int num_length = strchr(original, '#') - (original + 4);
char* num = malloc(num_length + 1);
strncpy(num, original + 4, num_length);
num[num_length] = 0;
Use a regular expression :)
#include <regex.h>
regcomp() // compile your regex
regexec() // run your regex
regfree() // free your regex
:)
Have a look into the strtok or strtok_r functions.
Here is something that will deal with a variable width substring, which doesn't care about the starting position of the substring. For instance, if string was iax2:xxx#xx.xx.xx.xx, it would still work. It will, however return NULL if either delimiter can't be found.
It uses strchr() to find the delimiters, which lets us know where to start copying and where to stop. It returns an allocated string, the calling function must free() the returned pointer.
I'm pretty sure this is what you want?
Note: Edited from original to be more re-usable and a bit saner.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *extract_string(const char *str, const char s1, const char s2)
{
char *ret = NULL, *pos1 = NULL, *pos2 = NULL;
size_t len;
if (str == NULL || s1 < 0 || s2 < 0)
return NULL;
pos1 = strchr(str, s1);
pos2 = strchr(str, s2);
if (! pos1 || ! pos2)
return NULL;
len = ((pos2 - str) - (pos1 - str) - 1);
ret = (char *) malloc(len + 1);
if (ret == NULL)
return NULL;
memcpy(ret, str + (pos1 - str) + 1, len);
ret[len] = '\0';
return ret;
}
int main(void)
{
const char *string = "sip:12387654345443222118765#xxx.xxx.xxx.xxx";
char *buff = NULL;
buff = extract_string(string, ':', '#');
if (buff == NULL)
return 1;
printf("The string extracted from %s is %s\n" , string, buff);
free(buff);
return 0;
}
You could easily modify that to not care if the second delimiter is not found and just copy everything to the right of the first. That's an exercise for the reader.

Resources