Referencing pointers after a fork() call in C - c

So, I've got a function that loads up a char** variable with some string data. My goal is to fork the process, and print some of that data in the child, and some from the parent. However, I'm unable to reference the pointer after the fork() call.
I thought that fork() made a copy of the entire address space of the parent process, which seems that it would include the various stack pointers...
Essentially, my code currently looks like this:
load_data(char **data);
char** data;
load_data(data);
printf("String 0: %s\n", data[0]);
fork();
printf("String 0 again: %s\n", data[0]); /* Segfaults Here! */
Anyone have any ideas what I'm doing wrong? I've done a bit of google searching on this, and it seems what I'm doing should work - but it doesn't. Thus, I'm misunderstanding something fundamental...

You're doing bad pointer operations and just getting lucky on the first call - here's what the code should look like:
load_data(char **data);
char* data = NULL;
load_data(&data);
printf("String 0: %s\n", data);
fork();
printf("String 0 again: %s\n", data); /* Doesn't Segfault Here! */

In your case, data doesn't point anywhere. Using an uninitialized variable is undefined behaviour. Even if it changed inside the load_data function, the change wouldn't be visible outside.
You need to either make data point to something valid, or pass the address of data to the function to have the changes "return", as in load_data(char ***data).
Your code, with minimal changes to make it a complete program, "works" for me
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int load_data(char **data);
int main(void) {
char **data;
data = malloc(2 * sizeof *data);
assert(data && "no memory");
load_data(data);
printf("String 0: %s\n", data[0]);
fork();
printf("String 0 again: %s\n", data[0]);
return 0;
}
int load_data(char **data) {
data[0] = "one";
data[1] = "two";
return 2;
}
And a sample run
$ ./a.out
String 0: one
String 0 again: one
String 0 again: one

Related

How to understand the type of storage of a pointer

I have as an homework this task:
Given a void** ptr_addr write a function that return 0 if the type of storage of *ptr_addr is static or automatic and return 1 if the type of storage of *ptr_addr is dynamic.
The language of the code must be C.
The problem is that theoretically I know what the task is about but I don't know how to check the
previous condition with a code.
Thanks for the help!
Normally I don't do homework, but in cases like this I may make an exception.
Bear in mind that what I'm about to present is horrible code. Also it doesn't meet your requirements as stated — you'll have to adapt it for that. Also it may not meet your instructor's expectations: for an instructor demented enough to be assigning this task, I can't begin to guess his (her? its?) expectations. You may get dinged for using the technique I've presented, or for presenting someone else's work. Also I'm going to get dinged for presenting this code here on Stack Overflow, because no, it's nothing like portable or guaranteed to do anything, let alone to work. I have no idea whether it'll work on your system.
Nevertheless, and may God help me, I tested it, and it does "work" on a modern Debian Linux system.
#include <unistd.h>
extern etext, edata, end;
char *
mcat(void *p)
{
int dummy;
if(p < &etext)
return "text";
else if(p < &edata)
return "data";
else if(p < &end)
return "bss";
else if(p < sbrk(0))
return "heap";
else if(p > &dummy)
return "stack";
else return "?";
}
You'll get a good number of warnings if you compile this, which could theoretically be silenced using some explicit casts, but I think the warnings are actually pretty appropriate, given the nefariousness of this code.
How it works: on at least some Unix-like systems, etext, edata, and end are magic symbols corresponding to the ends of the program's text, initialized data, and uninitialized data segments, respectively. sbrk(0) gives you a pointer to the top of the heap that a traditional implementation of malloc is using. And &dummy is a good approximation of the bottom of the stack.
Test program:
#include <stdio.h>
#include <stdlib.h>
int g = 2;
int g2;
int main()
{
int l;
static int s = 3;
static int s2;
int *p = malloc(sizeof(int));
printf("g: %s\n", mcat(&g));
printf("g2: %s\n", mcat(&g2));
printf("main: %s\n", mcat(main));
printf("l: %s\n", mcat(&l));
printf("s: %s\n", mcat(&s));
printf("s2: %s\n", mcat(&s2));
printf("p: %s\n", mcat(p));
}
On my test system this prints
g: data
g2: bss
main: text
l: stack
s: data
s2: bss
p: heap
I'd like to post a different approach to solve the problem:
// this function returns 1 if ptr has been allocated by malloc/calloc/realloc, otherwise 0
int is_pointer_heap(void* ptr) {
pid_t p = fork();
if (p == 0) {
(void) realloc(ptr, 1);
exit(0);
}
int status;
(void) waitpid(p, &status, 0);
return (status == 0) ? 1 : 0;
}
I wrote this (bad) code very quickly (and there's lot of room for improvements), but I tested it and it seems to work.
EXPLANATION: realloc() will crash your process if the argument passed to it is not a malloc/calloc/realloc-allocated pointer. Here we create a new child process, we let the child process call realloc(); if the child process crashes, we return 0, otherwise we return 1.

How to use the H5LTget_attribute_string function?

I have asked this on the HDF Forum here but haven't received an answer (yet). So I thought I try my luck here.
I have created a small test file in Python (h5py) and want to use the H5LTget_attribute_string function to read an attribute from it. However, I'm not sure how to use this function.
My test file looks like this.
HDF5 "attr.h5" {
GROUP "/" {
DATASET "my_dataset" {
DATATYPE H5T_STD_I64LE
DATASPACE SIMPLE { ( 12 ) / ( 12 ) }
DATA {
(0): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
}
ATTRIBUTE "string_attr" {
DATATYPE H5T_STRING {
STRSIZE H5T_VARIABLE;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_UTF8;
CTYPE H5T_C_S1;
}
DATASPACE SCALAR
DATA {
(0): "this is a string"
}
}
}
}
}
Looking at the documentation of H5LT_GET_ATTRIBUTE it seems to me that I need to allocate a buffer and pass the address of the buffer as the last parameter, after which the H5LT_GET_ATTRIBUTE function would fill the buffer. My first attempt was therefore this.
#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"
int main()
{
herr_t status;
hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
assert(file_id >= 0);
char string[1024]; // assume buffer is large enough;
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
fprintf(stderr, "---- reading attribute ----\n");
status = H5LTget_attribute_string(file_id, "my_dataset",
"string_attr", string);
assert(status >= 0);
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
status = H5Fclose(file_id);
assert(status >= 0);
}
However this didn't work as expected, see the output below.
string :
pointer: 0x7ffe3f7ec770
---- reading attribute ----
string : #B�k2V
pointer: 0x7ffe3f7ec770
After some googling and experimenting I found out that the last parameter should be the address of the buffer. Then the H5LT_GET_ATTRIBUTE function will make the buffer point to the actual attribute value. The following function compiled with a warning but it gave the correct output.
#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"
int main()
{
herr_t status;
hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
assert(file_id >= 0);
char* string = NULL;
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
fprintf(stderr, "---- reading attribute ----\n");
status = H5LTget_attribute_string(file_id, "my_dataset",
"string_attr", &string);
assert(status >= 0);
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
status = H5Fclose(file_id);
assert(status >= 0);
}
Output
string : (null)
pointer: (nil)
---- reading attribute ----
string : this is a string
pointer: 0x559e9e3d1240
Now I am perfectly happy to use it like this, and I can cast to **char to get rid of the warning, but I would like to be sure that this is the expected behavior. Ideally the documentation should be updated.
So my questions are:
Is the second example correct?
How long is the data in the string buffer valid? That is, when is the memory released by the HDF lib? (E.g. when the file is closed)
Should I use strcpy to copy the string data before using it?
As pointed by Scot Breitenfeld (from the HDF group):
If you are reading a variable length string with H5LTget_attribute_string (H5T_VARIABLE) then you don’t need to allocate the string, just pass in a pointer and the library will handle the allocations. If you are reading a fixed length string then you need to allocate a string that is “large enough”.
So, (1) your second approach seems ok to me.
As for (2) and (3), I would bet you are responsible for freeing the buffer, so no need to copy it. However, to be sure, you can use a debugger to check if the library is accessing the buffer or, even better, use valgrind to find memory leaks (when you try not to free the buffer).
I don't do HDF5, but I do enough C to provide you some answers with a very high percentage of being what you look for.
Is the second example correct?
yes it is. first because it returns the right and expected result, second
because any library that will fill a string (aka: char *) will need you to provide the address of a pointer (aka: char **).
How long is the data in the string buffer valid?
It is valid for as long as your program runs. This memory has been allocated for you with the right size, so it is valid for the entire lifetime of your program but it is now your responsibility to free it.
If you need more details on that please respond/comment to that message saying so and we'll help you.
Should I use strcpy to copy the string data before using it?
No you don't the memory has been alocated for you, you can keep it as is :-)
Next step that I advise you to do:
Now that you found the issue in their doc you should contact them and tell them.

Pipe's write overwrites an allocated space of memory

My program it's pretty big, so I'll highlight the main problem and add some details about it.
First part of my code:
int myPipe[2]; //A global variable, so I don't have to pass it to future functions
int main(int argc, char *args[])
{
mode_t pUmask = umask(0000); //Obsolete variable to my problem
errno = 0; //Obsolete variable to my problem
char pattern[2500] = "Test1"; //Obsolete variable to my problem
int p = 0; //DEFAULT NUMBER OF PROCESSES
int deep = 0; //Obsolete variable to my problem
int n = 1; //Obsolete variable to my problem
if(pipe(myPipe))
{
perror("Pipe Error: ");
exit(-1);
}
if( (write(myPipe[1], &p, (sizeof(int)*3))) == -1) //First write works
{
perror("write: ");
exit(-1);
}
//Then a bunch of code releated to file reading
}
Second part:
{
//in another function
//The part where I create fileName
char* fileName = calloc(strlen(fileData->d_name)+4, sizeof(char));
strcpy(fileName, fileData->d_name);
}
Third part:
//in another another function
if(S_ISREG(data.st_mode))
{
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
printf("\t\tOh boy! It's a regular.\n");
printf("\tfileName: %s\n", fileName); //Regular print of the right fileName
if((read(myPipe[0], &p, (sizeof(int)*3))) == -1) //First time I read
{
perror("\t\t read: ");
exit(-1);
}
printf("fileName: %s", fileName); //SEGMENTATION FAULT
There is a bunch of code in between, but it doesn't affect the fileName at all (in fact, up until the "read", fileName was printed flawlessly), and after it a SEGMENTATION FAULT happens.
At one point by changing the printfs locations I was able to get the fileName AFTER the read, which was basically the fileName value("File1") followed by the p integer value(0), which created the new corrupted fileName("File10").
So what's happening? I reserved the space for fileName, I passed the fileName pointer to the following functions up to that read, and supposedly the fd should have it's own adress space as well. HELP.
P.s. if you need more info, I'm willing to give it to you, even the full code, but it's REALLY complicated, and I think I gave you enough proof that fileName doesn't get corrupted at all until the read part, THANK YOU.
P.p.s.
I never close either of the "MyPipe" extremes, since I have to use them multiple times, I wanted to close them at the end of the program.
The statements that write and read the pipe are causing undefined behavior. p is declared:
int p;
But when you write and read it through the pipe, you use sizeof(int)*3, so you're accessing outside the object.
Change those statements to use just sizeof p.

pointers not read correctly

I am trying to get name of the input, output, and data files from the array for further processing. However, I am getting a weird error or problem. So, my program is not reaching the for loop. It does not even print the statement before the for loop. However, I tried using the debugger and the program is correctly printing step by step. So, when I run it does not print and when I debug step by step it prints. That is Weird!
char *method;
method=malloc(25);
method=NULL;
char *dataFileName;
char *inputMethod;
inputMethod=malloc(25);
inputMethod=NULL;
char *inputFileName;
char *outputMethod;
outputMethod=malloc(25);
outputMethod=NULL;
char *outputFileName;
char *commandArray[]={"if=q.txt","of=output.txt"};
char**args=(char**) malloc(sizeof(char*)*256);
args=commandArray;
int i;
printf("Before second for");
for(i=0;i<2;i++)
{
printf("I am here");
if(*args[i]=='d')
{
method=strtok_r(args[i],"=",&dataFileName);
printf("The method given is %s",method);
printf("Data File Name is %s",dataFileName);
}
else if(*args[i]=='o')
{
outputMethod=strtok_r(args[i],"=",&outputFileName);
printf("The output method given is %s",outputMethod);
printf("output File Name is %s",outputFileName);
}
else
{
inputMethod=strtok_r(args[i],"=",&inputFileName);
printf("The input method given is %s",inputMethod);
printf("Input File Name is %s",inputFileName);
}
}
if(method==NULL)
{
dataFileName=malloc(256);
printf("Please Enter A File Name");
scanf("%255s",dataFileName);
printf("%s",dataFileName);
}
if((inputMethod==NULL)||(outputMethod==NULL) )
{
char* array[]={"stdin","stdout"};
if(inputMethod==NULL)
inputMethod=array[0];
if(outputMethod==NULL)
outputMethod=array[1];
}
I am developing using Netbeans in C. The above code is written inside main. Thanks!
i intentionally left the previous answer because understanding memory allocation is trivial in programming in c specially. and as i see you have a big issue with that.
but still you have issue in nearly every thing. in my actual answer, i will try to simplify you how to use strtok, to split string and parse it. i guess this is the second main problem with your code.
the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char commandArray[][256]={
"if=q.txt",
"of=output.txt"
};
char infile[256], outfile[256];
for(int i=0; i<2;i++){
char *ptr,*cmd;
cmd=commandArray[i];
ptr=NULL;
printf("parsing command '%s'\n",cmd);
cmd=strtok(cmd,"=");
ptr=strtok(NULL,"=");
if(!cmd){
printf("Error parsing the string '%s'\n",commandArray[i]);
exit(1);
}
if (strcmp(cmd,"if")==0){
strcpy(infile,ptr);
}
else if (strcmp(cmd,"of")==0){
strcpy(outfile,ptr);
}
else{
printf("unknow token '%s'\n",cmd);
exit(1);
}
}
printf(
"\n\n"
"input file: '%s'\n"
"output file: '%s'\n"
"\n\n",
infile,outfile);
return 0;
}
the main problem is this:
char *method;
method=malloc(25);//allocating space for 25 char
method=NULL; // throwing up the allocation without freeing it;
// now the allocation is lost
// now method is useless (it is null)

Execve invoking

I want to invoke a shell in C program by execve:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
main()
{
char* path = "/bin/sh";
int err = execve(path, &path, NULL);
printf("%d\n", err);
printf("%s\n", strerror(errno));
printf("%x, %x\n", path, &path);
}
However the output is:
-1
Bad address
80485c0, bf816f4c
Because you aren't sending a NULL terminated list of arguments.
You need:
char* path[2];
path[0] = "/bin/sh";
path[1] = NULL;
int err = execve(path[0], path, NULL);
The second argument to execve is defined as being a NULL-terminated list of strings, so you can't simply pass the address of path. It expects an array like this, with the final entry being NULL:
arg[0] = "/bin/ls"
arg[1] = "-l"
arg[2] = "/usr/include/std*"
arg[3] = NULL
The reason it was failing with a bad pointer is that execve would have been looking at each word following path to find the arguments, and treating each word as a pointer until it got to the first 0 word. Since path was alone on the stack, it would have been trying to interpret whatever garbage happened to be in memory after the stack beyond path as a string pointer.
The solution is simple: you need to construct an array of parameters and add a NULL terminator (since it is of variable length). The fixed example is below (with a few warnings taken care of):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main()
{
char* path[] = { "/bin/sh", NULL };
int err = execve(path[0], path, NULL);
printf("%d\n", err);
printf("%s\n", strerror(errno));
printf("%p, %p\n", path, &path);
return 0;
}
Try this instead:
execl(path, path, NULL)
The exec family of functions will automatically execute a shell if the program is a script rather than a process image file. So you might be able to replace "path" with the pathname of the script.

Resources