C Pointer of array of strings garbled when retreived later - c

I have read a lot of the answers on the theoretical issues with memory allocation to pointer to arrays, but have not been able to fix my code...so turning to you.
I have an array of strings in a STRUCT, which I need to write to and read from. Declared as:
typedef struct client_mod
{
/* Client ad_file */
char *ad_filenames[10];
/* Client's current ad array index*/
unsigned int ad_index;
} client;
Then , inside a function , I assign values to pointer:
static int get_spots (client_mod *client)
{
char buf[512];
FILE *ptr;
if ((ptr = popen("php /media/cdn/getspot.php", "r")) != NULL) {
/* Read one byte at a time, up to BUFSIZ - 1 bytes, the last byte will be used for null termination. */
size_t byte_count = fread(buf, 1, 512 - 1, ptr);
/* Apply null termination so that the read bytes can be treated as a string. */
buf[byte_count] = 0;
}
(void) pclose(ptr);
// parse extracted string here...
int i = 0;
client->ad_filenames[i] = strdup(strtok(buf,"|"));
while(client->ad_filenames[i]!= NULL && i<5)
{
client->ad_filenames[++i] = strdup(strtok(NULL,"|"));
if (client->ad_filenames[i] != NULL && strlen(client->ad_filenames[i]) > 5) {
LOG("TESTING FOR CORRECT FILE NAMES %s\n", client->ad_filenames[i]);
}
}
}
The problem comes when I retreive the values later:
/* in looping code block */
LOG("Checking file under index = %d, file is %s", client->ad_index, client->ad_filenames[client->ad_index]);
The first two members of the array are retreived normally, everything after that is garbled.
I would appreciate any guidance. Thanks!
I understand this probablby comes from undefined behaviour of assigning directly to the pointer, but I can't figure out how to solve it.

I think the problem is with assigning to this struct element.
char *ad_filenames[10];
ad_filenames is an array of 10 of pointer to characters.
What that means is that memory allocation is needed for each index.
Something like
client->ad_filenames[0] = strdup(var1);
strdup() does both malloc() and strcpy() within this function.
client should be a variable name. You already defined client as a type.
Here is working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct client_mod
{
/* Client ad_file */
char *ad_filenames[10];
/* Client's current ad array index*/
unsigned int ad_index;
}CLIENT1;
CLIENT1 *client;
int func( char *var1 ) {
client->ad_filenames[0] = strdup(var1);
}
int
main(void)
{
char str1[10];
client = malloc( sizeof client );
strcpy( str1, "Hello" );
func( str1 );
printf("%s\n", client->ad_filenames[0] );
free(client->ad_filenames[0]);
free (client);
}

Your problem is with the line,
size_t byte_count = fread(buf, 1, 1000 - 1, ptr);
Read the man fread page,
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
you read 1000-1 members of size 1 into buf, which is only allocated buf[512], either expand buf or decrease fread 3rd argument,
buf[1000+1];
size_t byte_count = fread(buf, 1, sizeof(buf)-1, ptr);

Related

Printing the complete size of char*

I'm working on a C project, the goal is to reach a web server, read the data inside a file (example.com/shellcode.bin for example) and store it inside an array.
Currently, I managed to make the necessary GET requests, i can find my shellcode, insert it into an array (mycode) but when I return it, it sends me the wrong size.
For example, if sizeof(mycode) return 270, sizeof(PE) return 8.
Is it possible to find the total size of the PE variable ?
size_t size = sizeof(mycode);
char* PE = (char*)malloc(size);
for (int i = 0; i < sizeof(mycode); i++) {
PE[i] = mycode[i];
}
printf("Shellcode size before return : %ld\n", sizeof(PE));
return PE;
I tried different format string outputs (%s with strlen, %d, %ld, %zu ....) all of them returned 8.
One solution is to return a struct containing both a pointer to the buffer and the length.
// outside the function
typedef struct {
char* data;
size_t size;
} Buffer;
// in the function
Buffer buffer;
buffer.data = PE;
buffer.size = size;
return buffer;
And also change the return type to Buffer.
A pointer points to a single object of the pointed-to type; given a pointer value, there's no way to know whether you're looking at the first object of a sequence or not. There's no metadata in the pointer saying "there are N more elements following the thing I point to."
sizeof PE gives you the size of the pointer variable, not the number of things in the buffer; sizeof PE == sizeof (char *). sizeof *PE gives you the size of a single char object, which is 1 by definition; sizeof *PE == sizeof (char).
You have to manually keep track of how much memory you allocated - you somehow have to persist that size variable anywhere you intend to use PE.
As others have pointed out, you can bundle that into a struct type:
struct buffer {
size_t size;
char *PE;
};
struct buffer newBuf( const char *mycode, size_t size )
{
struct buffer b;
b.PE = calloc( size, sizeof *b.PE );
if ( b.PE )
{
memcpy( b.PE, mycode, size );
b.size = size;
}
return b;
}
int main( void )
{
char shellcode[] = { /* some char data here */ };
struct buffer b = newBuf( shellcode, sizeof shellcode );
...
}

How to read from pipe into a file?

I would like to read from the pipe straight into a file with the code below. base_fd is a pipe.
FILE* fp = fopen("dec_data", "wb+");
int r_result;
int len = msg_length-part-3; //set to 75933
while ((r_result = read(base_fd[0], fp, len))) {
printf("r_result: %d \n", r_result);
len -= r_result;
}
The read seems to happen fine, with r_result showing 65536 and then 10397 as required. However, when I inspect the file I created, it has a size of 0 bytes...
You have a semantic error in your code.
Take a look at the read(2) system call signature:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
The second parameter to the function is a void pointer (void *buf), which is where read will store the count bytes it reads from fd descriptor.
However, a FILE * is an abstraction of the C library. In this answer you can see more of it. The struct FILE in MinGW32 5.1.4 is:
typedef struct _iobuf
{
char* _ptr;
int _cnt;
char* _base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char* _tmpfname;
} FILE;
What read will do is similar to how we copy strings. Consider this function:
void strcpy(char *dst, char *src)
{
while(*src) *dst++ = *src++;
}
This function will copy the contents from src into dst until it finds a NULL terminating byte. This is obviously a very flawed function and should never be used, but illustrates why your example doesn't work.
Under the hood, what read is doing is very similar to this strcpy function: it is overwriting a lot of bytes in memory starting at the address pointed to by the fp pointer. You are effectively losing your reference to the FILE * pointer and the resources associated to it.
I'll bet that if you try to close(fp) after that loop you'll get a segmentation fault (it's Undefined Behavior, but I'll bet anyway).
The right way to do what you want is:
FILE* fp = fopen("dec_data", "wb+");
char *buf;
int r_result;
int len = msg_length - part - 3; //set to 75933
buf = malloc(len);
if(!buf) {
perror("malloc");
exit(EXIT_FAILURE);
}
while ((r_result = read(base_fd[0], buf, len))) {
fprintf(fp, buf);
len -= r_result;
}
free(buf);
close(fp); // now it closes the file pointer

Adding to an array in main via function argument

I'm not sure if I even worded the title correctly, but basically. I want to know if there is a way to add to the buff array from the hey function using the pointers in the arguments and why does it work if it does?
buf[100].
example:
int main(){
char buf[100];
hey("320244",buf);
printf("%s", buf);
}
void hey(char* s, char* result){
/*
some code that appends to result using pointers
do some stuff with s and get the result back in buf without using return.
*/
}
I have modified your code with some comments :-
#define LEN 100 //Use a macro instead of error prone digits in code
void hey(char* s, char* result); //Fwd declaration
int main(){
char buf[LEN] = {0}; //This will initialize the buffer on stack
hey("320244",buf);
printf("%s", buf);
hey("abc", buf); //Possible future invocation
printf("%s", buf);
}
void hey(char* s, char* result){
if(strlen(result) + strlen(s) < LEN ) //This will check buffer overflow
strcat(result, s); //This will concatenate s into result
else
//Do some error handling here
}
Let's do the right thing, and use a structure to describe a dynamically allocated, grow-as-needed string:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct mystring {
char *ptr; /* The actual string */
size_t len; /* The length of the string */
size_t max; /* Maximum number of chars allocated for */
};
#define MYSTRING_INIT { NULL, 0, 0 }
If we want to append something to a struct mystring, we define a function that takes a pointer to the structure the function can modify. (If it only needed a char pointer instead of a structure, it'd take a char **; a pointer to a char pointer.)
void mystring_append(struct mystring *ms, const char *s)
{
const size_t slen = (s) ? strlen(s) : 0;
/* Make sure ms points to a struct mystring; is not NULL */
if (!ms) {
fprintf(stderr, "mystring_append(): No struct mystring specified; ms == NULL!\n");
exit(EXIT_FAILURE);
}
/* Make sure we have enough memory allocated for the data */
if (ms->len + slen >= ms->max) {
const size_t max = ms->len + slen + 1;
char *ptr;
ptr = realloc(ms->ptr, max);
if (!ptr) {
fprintf(stderr, "mystring_append(): Out of memory!\n");
exit(EXIT_FAILURE);
}
ms->max = max;
ms->ptr = ptr;
}
/* Append. */
if (slen > 0) {
memmove(ms->ptr + ms->len, s, slen);
ms->len += slen;
}
/* We allocated one char extra for the
string-terminating nul byte, '\0'. */
ms->ptr[ms->len] = '\0';
/* Done! */
}
The (s) ? strlen(s) : 0; expression uses the ?: conditional operator. Essentially, if s is non-NULL, the expression evaluates to strlen(s), otherwise it evaluates to 0. You could use
size_t slen;
if (s != NULL)
slen = strlen(s);
else
slen = 0;
instead; I just like the concise const size_t slen = (s) ? strlen(s) : 0 form better. (The const tells the compiler that the slen variable is not going to be modified. While it might help the compiler generate better code, it is mostly a hint to other programmers that slen will have this particular value all through this function, so they do not need to check if it might be modified somewhere. It helps code maintenance in the long term, so it is a very good habit to get into.)
Normally, functions return success or error. For ease of use, mystring_append() does not return anything. If there is an error, it prints an error message to standard output, and stops the program.
It is a good practice to create a function that releases any dynamic memory used by such a structure. For example,
void mystring_free(struct mystring *ms)
{
if (ms) {
free(ms->ptr);
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
}
Often, you see initialization functions as well, like
void mystring_init(struct mystring *ms)
{
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
but I prefer initialization macros like MYSTRING_INIT, defined earlier.
You can use the above in a program like this:
int main(void)
{
struct mystring message = MYSTRING_INIT;
mystring_append(&message, "Hello, ");
mystring_append(&message, "world!");
printf("message = '%s'.\n", message.ptr);
mystring_free(&message);
return EXIT_SUCCESS;
}
Notes:
When we declare a variable of the structure type (and not as a pointer to the structure, i.e. no *), we use . between the variable name and the field name. In main(), we have struct mystring message;, so we use message.ptr to refer to the char pointer in the message structure.
When we declare a variable as a pointer to a structure type (as in the functions, with * before the variable name), we use -> between the variable name and the field name. For example, in mystring_append() we have struct mystring *ms, so we use ms->ptr to refer to the char pointer in the structure pointed to by the ms variable.
Dynamic memory management is not difficult. realloc(NULL, size) is equivalent to malloc(size), and free(NULL) is safe (does nothing).
In the above function, we just need to keep track of both current length, and the number of chars allocated for the dynamic buffer pointed to by field ptr, and remember that a string needs that terminating nul byte, '\0', which is not counted in its length.
The above function reallocates only just enough memory for the additional string. In practice, extra memory is often allocated, so that the number of reallocations needed is kept to a minimum. (This is because memory allocation/reallocation functions are considered expensive, or slow, compared to other operations.) That is a topic for another occasion, though.
If we want a function to be able to modify a variable (be that any type, even a structure) in the callers scope -- struct mystring message; in main() in the above example --, the function needs to take a pointer to variable of that type, and modify the value via the pointer.
The address-of operator, &, takes the address of some variable. In particular, &message in the above example evaluates to a pointer to a struct mystring.
If we write struct mystring *ref = &message;, with struct mystring message;, then message is a variable of struct mystring type, and ref is a pointer to message; ref being of struct mystring * type.
If I have understood you correctly you mean the following
#include <string.h>
//...
void hey(char* s, char* result)
{
strcpy( result, s );
}
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
void hey( const char* s, char* result);
int main(void)
{
char buf[100];
hey( "320244", buf );
printf( "%s\n", buf );
return 0;
}
void hey( const char* s, char* result )
{
strcpy( result, s );
}
Its output is
320244
If the array buf already stores a string then you can append to it a new string. For example
#include <string.h>
//...
char buf[100] = "ABC";
strcat( buf, "320244" );
Take into account that the function hey should be declared before its usage and according to the C Standard the function main shall be declared like
int main( void )

Issue with assignment from incompatible pointer type

Hey so im trying to attempt to read in a file, store it in a hash and then copy it. However i get the incompatible pointer type
struct hash_struct {
int id;
char name[BUFFER_SIZE]; /* key (string WITHIN the structure */
UT_hash_handle hh; /* makes this structure hashable */
};
int main(int argc, char *argv[] )
{
char *lines[80];
FILE* fp = fopen("file.txt","r");
if(fgets(*lines, BUFFER_SIZE, fp) != NULL)
{
puts(*lines);
// do something
}
fclose(fp);
const char **n;
char *names[1024];
strcpy(*names, *lines);
struct hash_struct *s, *tmp, *users = NULL;
int i=0;
for (n = names; *n != NULL; n++)
{
s = (struct hash_struct*)malloc(sizeof(struct hash_struct));
strncpy(s->name, *n,10);
s->id = i++;
HASH_ADD_STR( users, name, s );
}
HASH_FIND_STR( users, "joe", s);
if (s) printf("joe's id is %d\n", s->id);
printf("Hash has %d entries\n",HASH_COUNT(users));
/* free the hash table contents */
HASH_ITER(hh, users, s, tmp) {
HASH_DEL(users, s);
free(s);
}
return 0;
}
The code works when i initialize const char **n, *names = {array elements here};
But it doesnt work with the code i have. Please help.
lines is declared to be an array of char pointers, but doesn't allocate any space for the strings they point to. In your working version, the compiler took care of allocating space for each string.
Plus, you can't use strcpy to copy an array of 80 pointers to an array of 1024 pointers.
Instead, each line you read in needs space to be allocated for it to be read into; then the addresses of each of those can be assigned to an element of names. In fact, as #BLUEPIXY suggests, line should be an array of 80 chars, not an array of 80 pointers-to-chars. Or you could just malloc the space for each new line, and put the address of that line into names.

Copying a file line by line into a char array with strncpy

So i am trying to read a text file line by line and save each line into a char array.
From my printout in the loop I can tell it is counting the lines and the number of characters per line properly but I am having problems with strncpy. When I try to print the data array it only displays 2 strange characters. I have never worked with strncpy so I feel my issue may have something to do with null-termination.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[])
{
FILE *f = fopen("/home/tgarvin/yes", "rb");
fseek(f, 0, SEEK_END);
long pos = ftell(f);
fseek(f, 0, SEEK_SET);
char *bytes = malloc(pos); fread(bytes, pos, 1, f);
int i = 0;
int counter = 0;
char* data[counter];
int length;
int len=strlen(data);
int start = 0;
int end = 0;
for(; i<pos; i++)
{
if(*(bytes+i)=='\n'){
end = i;
length=end-start;
data[counter]=(char*)malloc(sizeof(char)*(length)+1);
strncpy(data[counter], bytes+start, length);
printf("%d\n", counter);
printf("%d\n", length);
start=end+1;
counter=counter+1;
}
}
printf("%s\n", data);
return 0;
}
Your "data[]" array is declared as an array of pointers to characters of size 0. When you assign pointers to it there is no space for them. This could cause no end of trouble.
The simplest fix would be to make a pass over the array to determine the number of lines and then do something like "char **data = malloc(number_of_lines * sizeof(char *))". Then doing assignments of "data[counter]" will work.
You're right that strncpy() is a problem -- it won't '\0' terminate the string if it copies the maximum number of bytes. After the strncpy() add "data[counter][length ] = '\0';"
The printf() at the end is wrong. To print all the lines use "for (i = 0; i < counter; i++) printf("%s\n", data[counter]);"
Several instances of bad juju, the most pertinent one being:
int counter = 0;
char* data[counter];
You've just declared data as a variable-length array with zero elements. Despite their name, VLAs are not truly variable; you cannot change the length of the array after allocating it. So when you execute the lines
data[counter]=(char*)malloc(sizeof(char)*(length)+1);
strncpy(data[counter], bytes+start, length);
data[counter] is referring to memory you don't own, so you're invoking undefined behavior.
Since you don't know how many lines you're reading from the file beforehand, you need to create a structure that can be extended dynamically. Here's an example:
/**
* Initial allocation of data array (array of pointer to char)
*/
char **dataAlloc(size_t initialSize)
{
char **data= malloc(sizeof *data * initialSize);
return data;
}
/**
* Extend data array; each extension doubles the length
* of the array. If the extension succeeds, the function
* will return 1; if not, the function returns 0, and the
* values of data and length are unchanged.
*/
int dataExtend(char ***data, size_t *length)
{
int r = 0;
char **tmp = realloc(*data, sizeof *tmp * 2 * *length);
if (tmp)
{
*length= 2 * *length;
*data = tmp;
r = 1;
}
return r;
}
Then in your main program, you would declare data as
char **data;
with a separate variable to track the size:
size_t dataLength = SOME_INITIAL_SIZE_GREATER_THAN_0;
You would allocate the array as
data = dataAlloc(dataLength);
initially. Then in your loop, you would compare your counter against the current array size and extend the array when they compare equal, like so:
if (counter == dataLength)
{
if (!dataExtend(&data, &dataLength))
{
/* Could not extend data array; treat as a fatal error */
fprintf(stderr, "Could not extend data array; exiting\n");
exit(EXIT_FAILURE);
}
}
data[counter] = malloc(sizeof *data[counter] * length + 1);
if (data[counter])
{
strncpy(data[counter], bytes+start, length);
data[counter][length] = 0; // add the 0 terminator
}
else
{
/* malloc failed; treat as a fatal error */
fprintf(stderr, "Could not allocate memory for string; exiting\n");
exit(EXIT_FAILURE);
}
counter++;
You are trying to print data with a format specifier %s, while your data is a array of pointer s to char.
Now talking about copying a string with giving size:
As far as I like it, I would suggest you to use
strlcpy() instead of strncpy()
size_t strlcpy( char *dst, const char *src, size_t siz);
as strncpy wont terminate the string with NULL,
strlcpy() solves this issue.
strings copied by strlcpy are always NULL terminated.
Allocate proper memory to the variable data[counter]. In your case counter is set to 0. Hence it will give segmentation fault if you try to access data[1] etc.
Declaring a variable like data[counter] is a bad practice. Even if counter changes in the subsequent flow of the program it wont be useful to allocate memory to the array data.
Hence use a double char pointer as stated above.
You can use your existing loop to find the number of lines first.
The last printf is wrong. You will be printing just the first line with it.
Iterate over the loop once you fix the above issue.
Change
int counter = 0;
char* data[counter];
...
int len=strlen(data);
...
for(; i<pos; i++)
...
strncpy(data[counter], bytes+start, length);
...
to
int counter = 0;
#define MAX_DATA_LINES 1024
char* data[MAX_DATA_LINES]; //1
...
for(; i<pos && counter < MAX_DATA_LINES ; i++) //2
...
strncpy(data[counter], bytes+start, length);
...
//1: to prepare valid memory storage for pointers to lines (e.g. data[0] to data[MAX_DATA_LINES]). Without doing this, you may hit into 'segmentation fault' error, if you do not, you are lucky.
//2: Just to ensure that if the total number of lines in the file are < MAX_DATA_LINES. You do not run into 'segmentation fault' error, because the memory storage for pointer to line data[>MAX_DATA_LINES] is no more valid.
I think that this might be a quicker implementation as you won't have to copy the contents of all the strings from the bytes array to a secondary array. You will of course lose your '\n' characters though.
It also takes into account files that don't end with a new line character and as pos is defined as long the array index used for bytes[] and also the length should be long.
#include <stdio.h>
#include <stdlib.h>
#define DEFAULT_LINE_ARRAY_DIM 100
int main(int argc, char* argv[])
{
FILE *f = fopen("test.c", "rb");
fseek(f, 0, SEEK_END);
long pos = ftell(f);
fseek(f, 0, SEEK_SET);
char *bytes = malloc(pos+1); /* include an extra byte incase file isn't '\n' terminated */
fread(bytes, pos, 1, f);
if (bytes[pos-1]!='\n')
{
bytes[pos++] = '\n';
}
long i;
long length = 0;
int counter = 0;
size_t size=DEFAULT_LINE_ARRAY_DIM;
char** data=malloc(size*sizeof(char*));
data[0]=bytes;
for(i=0; i<pos; i++)
{
if (bytes[i]=='\n') {
bytes[i]='\0';
counter++;
if (counter>=size) {
size+=DEFAULT_LINE_ARRAY_DIM;
data=realloc(data,size*sizeof(char*));
if (data==NULL) {
fprintf(stderr,"Couldn't allocate enough memory!\n");
exit(1);
}
}
data[counter]=&bytes[i+1];
length = data[counter] - data[counter - 1] - 1;
printf("%d\n", counter);
printf("%ld\n", length);
}
}
for (i=0;i<counter;i++)
printf("%s\n", data[i]);
return 0;
}

Resources