Vulnerability of malloc and memcpy - c

void *copy_elements(void *ele_src[], int ele_cnt, size_t ele_size)
{
/*
* Allocate buffer for ele_cnt objects, each of ele_size bytes
* and copy from locations designated by ele_src
*/
void *result = malloc(ele_cnt * ele_size);
if (result == NULL)
/* malloc failed */
return NULL;
void *next = result;
int i;
for (i = 0; i < ele_cnt; i++) {
/* Copy object i to destination */
memcpy(next, ele_src[i], ele_size);
/* Move pointer to next memory region */
next += ele_size;
}
return result;
}
The above code has a vulnerability issue. Under some ele_cnt and ele_size values, the code might crash. I suspect it has to do with unsigned - signed conversion that happens with malloc and memcpy but I'm not sure how to exploit this properly. Any help would be thankful!

There are multiple issues with the posted code:
since ele_cnt is defined with a signed type, one should test if the value passed is negative or zero and return NULL without attempting to allocate a huge amount of memory, which may cause a runtime error.
for defensive coding, ele_size should not be zero either.
next += ele_size; is invalid as next has void * type. Some compilers allow it as an extension, but the code is not portable.
copying the elements one at a time is inefficient, a single call to memcpy suffices.
Here is a modified verion:
#include <stdlib.h>
#include <string.h>
void *copy_elements(const void *ele_src[], int ele_cnt, size_t ele_size)
{
/*
* Allocate buffer for ele_cnt objects, each of ele_size bytes
* and copy from locations designated by ele_src
*/
void *result;
if (ele_cnt <= 0 || ele_size == 0) {
/* invalid arguments */
return NULL;
}
if ((result = malloc(ele_cnt * ele_size)) == NULL) {
/* malloc failure */
return NULL;
}
/* copy all elements with a single call to memcpy */
return memcpy(result, ele_src, ele_cnt * ele_size);
}

I think the problems is next += ele_size is not as you suppose. When you adding pointer, it automatically multiply with offset. You can print next value in for loop so you can check if it true using printf("%p", next)

Related

Dynamic array of structs in C using realloc

I'm trying to create a simple dynamic array of structures, but I'm unsure about how to go about doing it.
I have
n = 1;
typedef struct {
char wordName [50];
int counter;
}Words;
Words * array;
And now I want to reallocate it in this loop.
if(strlen(token) > 6){
array = (Words*)realloc(array, sizeof(Words)*n++);
strcpy(array->wordName, token);
//printf("%s ", array->wordName);
array++;
}
I can add data to the structure, it prints it all out in a loop just fine. But when I add array++, I get:
realloc(): invalid pointer
Am I accessing the data incorrectly? Or do I not even have any more pointers beyond the head?
array++; causes array to advance by sizeof (a_pointer) so it now no longer points to address first returned by realloc(). That means any future attempt to realloc() with the new address of array will result in the error "Invalid pointer, pointer was not initially allocated with call to malloc, calloc or realloc".
Further, if array is not initialized NULL, then you cannot use realloc() for the initial allocation. Initializing n = 1; mixes a count with and index. Always keep the count so it is the next index to be filled. For 0 you can use an if / else or ternary, e.g.
n = 0;
...
if (n) { /* if n > 0 (not 1st allocation, use realloc) */
/* always realloc using a temporary pointer */
void *tmp = realloc (array, (n + 1) * sizeof *array);
if (!tmp) { /* validate EVERY allocation */
/* handle error, return */
}
array = tmp; /* assign reallocated block to array */
n += 1; /* increment count */
}
else { /* initial allocation */
array = malloc (sizeof *array);
if (!array) { /* validate EVERY allocation */
/* handle error, return */
}
n += 1; /* increment count */
}
/* rest of your strcpy here
* VALIDATE strlen(token) > 0 AND < 50
*/
/* note: you can consolidate both n += 1; here. duplicated for clarity */
You always call realloc() with a temporary pointer because when (not if) realloc() fails it returns NULL which will overwrite the address pointing to the allocated block of memory creating a memory leak. e.g. never do:
pointer = realloc (pointer, size);
Instead, by using a temporary pointer, if realloc() fails, pointer (your array) will still point to the last allocated and still valid block of memory allowing you to use what is stored there AND allowing you to free() that block of memory when you are done with it.
Note, you can use a ternary, but it is much less readable:
Words *array = NULL;
size_t n = 0;
...
void *tmp = realloc (array, sizeof *array * n ? n + 1 : 1);
if (!tmp) { /* validate EVERY allocation */
/* handle error, return */
}
array = tmp;
n += 1;
/* rest of your strcpy here
* VALIDATE strlen(token) > 0 AND < 50
*/
In C, there is no need to cast the return of malloc (or calloc or realloc), it is unnecessary. See: Do I cast the result of malloc?

How can I get my program to produce zsh:abort error instead of writting random characters?

I am trying to replicate memcpy function, but when I try with NULL as both parameters but with size (5 for example) the original function gives the abort error but my program writes random characters.
void *ft_memcpy(void *dst, const void *src, size_t n)
{
size_t i;
char *d;
char *s;
s = (char*)src;
d = (char*)dst;
i = 0;
while (i < n)
{
d[i] = s[i];
i++;
}
i = 0;
return (dst);
}
int main()
{
char dst[0];
char src[0];
size_t n = 5;
printf("%s", ft_memcpy(dst, src, n));
printf("%s\n", memcpy(dst, src, n));
return (0);
}
src and dst have size 0, which is one way of specifying flexible arrays in C. You usually only define them inside structures that are going to be dynamically allocated, for example:
struct buffer {
size_t len;
char bytes[0]
};
#define NBYTES 8
struct buffer* ptr = malloc(sizeof(struct buffer) + NBYTES * sizeof(char));
const char* src = "hello!";
ptr->len = strlen(src);
memcpy(ptr->bytes, src, ptr->len);
Basically, indexing any of those arrays in your example will end up in a buffer overflow (you are accessing beyond the limits of the array).
The difference between this and passing NULL as parameters is that src and dst point to valid memory (main function stack). In C a buffer overflow has no defined behaviour (undefined behaviour), so the compiler is free to do what it wants. If you use a memory sanitizer (compile with -fsanitize=address) it will warn you about this problem and ask you to fix the error.
I recommend you using a debugger or add the following print statements in your copy function:
printf("%s: src: %p, dst: %p\n", __func__, src, dst);
See Array of zero length
Update: since you asked how to generate the abort error, the easiest and most convenient way for this scenario is using assertions.
#include <assert.h>
void function(void *addr) {
assert(addr != NULL);
}
will abort the execution if the condition addr != NULL evaluates to false.
Assertions are very useful to expose what conditions you assume will always be valid and for whom you don't want to pay the cost of checking them when you build the code for production, since these checks may have a performance impact. You can disable them by compiling with the flag -DNDEBUG.
See also: When should we use asserts in C?
Another way is making the program to simply abort:
#include <cstdlib.h>
void function(void *addr) {
if(addr == NULL) abort();
}
or to set errno variable to EINVAL:
#include <errno.h>
void function(void *addr) {
if (addr == NULL) {
errno = EINVAL;
return;
}
}

How do you return a pointer from a function outside of main()

My question is aboutt dynamic memory allocation in C. I have been asked to dynamically allocate an array of n longs, and return the pointer to the first element of this array. I have some code to test the output of this but the memory allocation is failing.
long* make_long_array(long n)
{
int i;
int *a;
a = (int*)malloc(sizeof(int)*n);
if (a == NULL) {
printf("ERROR: Out of memory\n");
return 1;
}
for (i = 0; i < n; *(a + i++) = 0);
return *a;
}
Im getting an error on two lines saying
'error: return makes pointer from integer without cast'
this occurs for the lines
return 1;
and
return *a;
I'm not entirely sure how to fix this. I think the error in return 1; being that I am trying to return an integer when it is looking for a pointer? But I am not sure how to fix it for the return of the pointer. Any help would be much appreciated.
To fix your original version:
long* make_long_array(/* long not the correct type for sizes of objects */ size_t n)
{
// int i; define variables where they're used.
/* int you want to return a */ long *a; // array.
a = /* (int*) no need to cast */ malloc(sizeof(/* int */ you want */ long /*s, remember? *) */ ) * n);
if (a == NULL) {
printf("ERROR: Out of memory\n"); // puts()/fputs() would be sufficient.
return /* 1 */ NULL; // 1 is an integer. Also it is uncommon to return
} // anything other than NULL when a memory allocation
// fails.
for (size_t i = 0; i < n; /* *(a + i++) = 0 that falls into the category obfuscation */ ++i )
/* more readable: */ a[i] = 0;
// return *a; you don't want to return the first long in the memory allocated
return a; // but the address you got from malloc()
}
A Better Waytm to write such allocations is
FOO_TYPE *foo = malloc(NUM_ELEMENTS * sizeof(*foo)); // or
BAR_TYPE *bar = calloc(NUM_ELEMENTS, sizeof(*bar));
By using *foo and *bar as the operand of sizeof you don't have to worry about changing it when the type of foo or bar changes.
Your function can be simplified to
#include <stddef.h> // size_t
#include <stdlib.h> // calloc()
long* make_long_array(size_t size) // size_t is guaranteed to be big enough to hold
{ // all sizes of objects in memory and indexes
return calloc(size, sizeof(long)); // into them. calloc() initializes the memory
} // it allocates with zero.
// if you really want an error-message printed:
long* make_long_array(size_t size)
{
long *data = calloc(size, sizeof(long));
if (!data) // calloc() returned NULL
fputs("Out of memory :(\n\n", stderr); // Error messages should go to stderr
return data; // since it is unbuffered*) and
} // might be redirected by the user.
*) so the user gets the message instantly.
Also there is no need to cast the result of *alloc() since they return a void* which is implicitly convertible in every other pointer type.
Could be written as a macro so it not only works for long but for any type:
#include <stddef.h>
#include <stdlib.h>
#define MAKE_ARRAY(TYPE, COUNT) calloc((COUNT), sizeof((TYPE)))
// sample usage:
int main(void)
{
int *foo = MAKE_ARRAY(*foo, 12);
long *bar = MAKE_ARRAY(*bar, 24);
char *qux = MAKE_ARRAY(*qux, 8);
free(qux);
free(bar);
free(foo);
}

Seg fault using struct

I have been writing C for approximately a week, so bear with me. I'm getting a segmentation fault error in the method assemble_url and I dont know why. Here is my code:
/** Includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h>
/** Definitions */
#define MAX_OPTIONS 32
#define MAX_ARGS 32
/** Command option */
typedef struct {
char *argname;
char *value;
} command_option;
/** Command */
typedef struct {
command_option options[MAX_OPTIONS];
} command_t;
/**
* Prints the arguments passed in in a hashmap format (key => value)
*/
void populate_command(command_t *cmd,int argc,char *argv[])
{
int i,j=0;
/** Check to see if we have arguments. If argc is equal to 1 than there are no arguments besides the filename */
if(argc>1)
{
/* Start at position 1, since argv[0] is the filename being called */
for(i=1;i<argc;i++)
{
/* Head of argv array */
char *arg = argv[i];
/* Create a copy of head for traversal. */
char *c = arg;
/* traverse the char array, ensuring we arent dealing with NULL values(c!==NULL) and NULL pointers(*c!=='\0') */
while(*c != '\0' && c != NULL)
{
/* Were only concerned with parsing the flags and obtaining the flag value. */
if(strchr("-",*c))
{
char *key = c; /* Key */
char *value = argv[i+1]; /* Value */
/* ensure we have a value existent for key */
if(strchr("-",*value))
{
/** user supplied a key with no value */
break;
}
command_option *option = &cmd->options[j];
option->argname = key;
option->value = value;
j++;
/* Debug dump */
printf("arg %d: %s -> %s\n",i,option->argname,option->value);
}/* end strchr */
/** Increment the traversal array */
c++;
}/* end while loop */
}/* end forloop */
}/* endif */
}/** end print_args */
/**
* Concatenates two strings and returns the resulting concatenated string
*/
char* concatstring(char *s1,char *s2)
{
/* Allocate memory for *result. We add 1 to account for the extra byte to store the null character. Strlen accounts for all
non-null bytes, so using strlen(s1) + strlen(s2) + 1 ensures that an overflow wont occur. An overflow occurs when
the number of bytes being used (in our example, is the addition of strlen for s1 and s2) is more than the number of bytes
allocated (in our example, the number of bytes allocated to *result)*/
char *result = malloc(strlen(s1)+strlen(s2)+1);
/*Copies the C string pointed by source(s1) into the array pointed by destination(result), including the terminating null character. */
strcpy(result,s1);
/* appends a copy of the source string(s2) to the destination string(result). The terminating null character in
destination is overwritten by the first character of source, and a null-character is included at
the end of the new string formed by the concatenation of both in destination.*/
strcat(result,s2);
/* return result */
return result;
} /** end concatstring */
char* assemble_url(command_t *cmd,char *str)
{
int i,opt_len = sizeof(&cmd->options);
for(i=0;i<opt_len;i++)
{
command_option *option = &cmd->options[i];
char *key = option->argname;
char *value = option->value;
if(i==0)
{
str = concatstring(str,key);
str = concatstring(str,"=");
str = concatstring(str,value);
}
else
{
str = concatstring(str,"&");
str = concatstring(str,key);
str = concatstring(str,"=");
str = concatstring(str,value);
}
}
return str;
}
What occurs in this program is the following:
1./ User types in program name and flag options,such as the following:
program -test a -test2 b
2./ The program parses the command and populates a command struct with options. Each option has a flag(argname) and value associated to it(value)
3./ The program then tries to create a URL with those option keys and values, such as http://url/?test=a&test2=b
The program compiles but I'm still new to pointers and references (I think & is called a reference), so maybe that is why the program errors.
Any help is greatly appreciated! Also, if you see any probems or better way to handle assemble_url, please also let me know (I dont think its being handled in the best way, but like I said, I'm extremely new to C programming)
Thanks!
This initialization
int opt_len = sizeof(&cmd->options);
will give you the byte-size of a pointer &cmd->options. This makes no sense in the context of what you are trying to do.
If you want to determine the number of elements in an array (assuming it hasn't decayed to pointer), the proper technique would be
int opt_len = sizeof cmd->options / sizeof *cmd->options;
In this case opt_len will be initialized with MAX_OPTIONS value (meaning that you can just use MAX_OPTIONS in its place).
You have massive memory leaks from concatstring. Each invocation allocates a new buffer but you never bother to free them, and you loose the pointers so no chance of ever freeing that memory again.
This is not the cause of the segfault.
Because you are concatenating more than two strings it would be best if you allocated memory for all concatenations at once.
#include <stdarg.h>
#include <string>
char* stringBuilder(int count, ...)
{
va_list ap, vacnt;
int j;
int len = 1;
char* buffer;
va_start(ap, count);
#ifdef va_copy
va_copy(vacnt,ap);
#else
vacnt = ap;
#endif
for(j=0; j<count; ++j){
len+=strlen(va_arg(vacnt, char*));
}
va_end(vacnt);
buffer = (char*) malloc(len * sizeof(char));
buffer[0]=0;
for (j=0;j<count;++j) {
strcat (buffer, va_arg(ap, char*));
}
va_end(ap);
return buffer;
}
You can use it as such:
char* x = stringBuilder(4,"hello", " ", "world", "\n");
printf(x);
free(x);
Also note that both key and value must be URL-Encoded for the purposes of your application

Returning a character array from a function in c

Can I return an array that is created dynamically (using malloc) inside a function back to its caller?
I know that returning a statically allocated array is wrong because the stack unwinds as the function returns and variable is no longer valid but what about a dynamically allocated variable?
Returning anything allocated with malloc is fine, as long as whoever uses your function takes care of free()ing it when they're done. malloc allocates on the heap which is essentially global within your program.
As others have noted, you can in fact return a char pointer.
However, another common method is for the caller to pass in the pointer for the method to fill along with a length parameter. This makes it so the function responsible for allocating the memory will also be the same function responsible for freeing the memory, which can make memory leaks easier to see. This is what functions such as snprintf and strncpy do.
/* Performs a reverse strcpy. Returns number of bytes written if dst is
* large enough, or the negative number of bytes that would have been
* written if dst is too small too hold the copy. */
int rev_strcpy(char *dst, const char *src, unsigned int dst_len) {
unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */
int i,j;
if (src_len+1 > dst_len) {
return -(src_len+1); /* +1 for terminating NULL */
}
i = 0;
j = src_len-1;
while (i < src_len) {
dst[i] = src[j];
++i;
++j;
}
dst[src_len] = '\0';
return src_len;
}
void random_function() {
unsigned int buf_len;
char *buf;
int len;
const char *str = "abcdefg";
buf_len = 4;
buf = malloc(buf_len * sizeof(char));
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
/* ...whatever randomness this function needs to do */
len = rev_strcpy(buf, str, buf_len);
if (len < 0) {
/* realloc buf to be large enough and try again */
free(buf);
buf_len = -len;
buf = malloc(buf_len * sizeof(buf));
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
len = rev_strcpy(buf, str, sizeof(buf));
}
/* ... the rest of the randomness this function needs to do */
/* random_function has allocated the memory, random_function frees the memory */
free(buf);
}
This can lead to some overhead though if you don't know how big a buffer you'll need and need to call the function twice, but often the caller has a good idea to how large the buffer needs to be. Also it requires a little more logic to ensure the function doesn't overrun the given buffer. But it keeps the responsibility of freeing the memory with whatever is allocating the memory, while also allowing the option to pass local stack memory.
Example just returning the char*:
/* Performs a reverse strcpy. Returns char buffer holding reverse copy of
* src, or NULL if memory could not be allocated. Caller is responsible
* to free memory. */
char* rev_strcpy(const char *src) {
unsigned int src_len = strlen(src); /* assumes src is in fact NULL-terminated */
char *dst;
int i,j;
dst = malloc((src_len+1) * sizeof(char));
if (!dst) {
return NULL;
}
i = 0;
j = src_len-1;
while (i < src_len) {
dst[i] = src[j];
++i;
++j;
}
dst[src_len] = '\0';
return dst;
}
void random_function() {
char *buf;
const char *str = "abcdefg";
/* ...whatever randomness this function needs to do */
buf = rev_strcpy(str);
if (!buf) {
/* fail hard, log, whatever you want */
return;
}
/* ... the rest of the randomness this function needs to do */
/* random_function frees the memory that was allocated by rev_strcpy */
free(buf);
}
Yes you can. Just malloc() the array inside your function and return the pointer.
BUT, the caller needs to understand it needs to be freed at some point, or you'll have a memory leak.
You can certainly return an array allocated with malloc, but you have to make sure the caller of the function eventually releases the array with free; if you don't free a malloc'd array, the memory remains "in use" until program exit.

Resources