segfault w/ block, but not file scope

D

Dieter

Hi.

In the snippet of code below, I'm trying to understand why when the

struct dirent ** namelist

is declared with "file" scope, I don't have a problem freeing the
allocated memory. But when the struct is declared in main (block scope)
it will segfault when passing namelist to freeFileNames().

Since this seems to be just a matter of my understanding scope and
pointer parameter passing better, I only included what thought to be
relevant code. I'll happily provide compilable code if deemed necessary.

Please see commented lines:


struct dirent **namelist; /* file scope works */

int main(void)
{
/* struct dirent **namelist */ /* block scope doesn't work */
int n;

n = getFileNames(H5DIR, namelist); /* included from mylib.h */
freeFileNames(namelist, n); /* included from mylib.h */

return 0;
}


Thank you very much for your comments,
Dieter
 
D

Dieter

Dieter said:
Hi.

In the snippet of code below, I'm trying to understand why when the

struct dirent ** namelist

is declared with "file" scope, I don't have a problem freeing the
allocated memory. But when the struct is declared in main (block scope)
it will segfault when passing namelist to freeFileNames().

Since this seems to be just a matter of my understanding scope and
pointer parameter passing better, I only included what thought to be
relevant code. I'll happily provide compilable code if deemed necessary.

Please see commented lines:


struct dirent **namelist; /* file scope works */

int main(void)
{
/* struct dirent **namelist */ /* block scope doesn't work */
int n;

n = getFileNames(H5DIR, namelist); /* included from mylib.h */
freeFileNames(namelist, n); /* included from mylib.h */

return 0;
}


Thank you very much for your comments,
Dieter

Here's the actual code if needed. Although dirent.h is platform
specific, I think my question is relative to standard C.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>

#define H5DIR "/home/stella/data/h5/rawTables"

int getFileNames(char *directory, struct dirent **namelist);
int freeFileNames(struct dirent **namelist, int entries);

struct dirent **namelist;

int main(void)
{
int n;

n = getFileNames(H5DIR, namelist);
printf("%d\n",n);
err = freeFileNames(namelist, n);
if (err==0)
printf("There wasn't any files");
return 0;
}

int getFileNames(char *directory, struct dirent **namelist)
{
int n, i;

n = scandir(directory, &namelist, 0, alphasort);
if(n == -1){
perror("scandir returned: ");
exit(1);
}
if(n == 0){
printf("No files found. Quiting.\n\n");
exit(1);
}
for (i=0;i<n;i++){
printf("File: %s\n", namelist->d_name);
}

return n;
}

int freeFileNames(struct dirent **namelist, int entries)
{
int i;

if (namelist == NULL)
return 0;
else{
printf("%d",entries);
for (i = 0; i < entries; i++){
free(namelist);
namelist = NULL;
printf("%d,", i);
}
puts("\n");
free(namelist);
namelist = NULL;
}

return 1;
}
 
J

Jack Klein

Here's the actual code if needed. Although dirent.h is platform
specific, I think my question is relative to standard C.

The actual code is not needed, and is indeed off-topic. Your problem
has a great deal to do with how the function scandir(), which is
apparently from dirent.h, deals with pointers.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>

#define H5DIR "/home/stella/data/h5/rawTables"

int getFileNames(char *directory, struct dirent **namelist);
int freeFileNames(struct dirent **namelist, int entries);

struct dirent **namelist;

When you define this pointer a file scope, it has static storage
duration and is therefore initialized to NULL. When you define it
inside a function, it has automatic storage duration by default and it
not initialized at all.
int main(void)
{
int n;

n = getFileNames(H5DIR, namelist);
printf("%d\n",n);
err = freeFileNames(namelist, n);
if (err==0)
printf("There wasn't any files");
return 0;
}

int getFileNames(char *directory, struct dirent **namelist)
{
int n, i;

n = scandir(directory, &namelist, 0, alphasort);

[snip]

On the last line of code above, you pass a pointer to 'namelist'
(therefore a char ***) to scandir(). Presumably this function checks
whether the pointed-to char ** is NULL or not, and if it is NULL, it
allocates the necessary memory. And also presumably, if the
pointed-to char ** is not NULL, it assumes that it points to valid
memory and uses it. At the end you try to free a pointer that was not
allocated.

I would suggest that you study the documentation for the function
scandir() and see what the requirements are for that parameter.
 
D

Dieter

Jack said:
Here's the actual code if needed. Although dirent.h is platform
specific, I think my question is relative to standard C.


The actual code is not needed, and is indeed off-topic. Your problem
has a great deal to do with how the function scandir(), which is
apparently from dirent.h, deals with pointers.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>

#define H5DIR "/home/stella/data/h5/rawTables"

int getFileNames(char *directory, struct dirent **namelist);
int freeFileNames(struct dirent **namelist, int entries);

struct dirent **namelist;


When you define this pointer a file scope, it has static storage
duration and is therefore initialized to NULL. When you define it
inside a function, it has automatic storage duration by default and it
not initialized at all.

int main(void)
{
int n;

n = getFileNames(H5DIR, namelist);
printf("%d\n",n);
err = freeFileNames(namelist, n);
if (err==0)
printf("There wasn't any files");
return 0;
}

int getFileNames(char *directory, struct dirent **namelist)
{
int n, i;

n = scandir(directory, &namelist, 0, alphasort);


[snip]

On the last line of code above, you pass a pointer to 'namelist'
(therefore a char ***) to scandir(). Presumably this function checks
whether the pointed-to char ** is NULL or not, and if it is NULL, it
allocates the necessary memory. And also presumably, if the
pointed-to char ** is not NULL, it assumes that it points to valid
memory and uses it. At the end you try to free a pointer that was not
allocated.

I would suggest that you study the documentation for the function
scandir() and see what the requirements are for that parameter.

Jack, I sincerely thank you for commenting.

NULL initialization was certainly an issue.

Dieter
 
M

M.B

Dieter said:
relevant code. I'll happily provide compilable code if deemed necessary.

Please see commented lines:


struct dirent **namelist; /* file scope works */

int main(void)
{
/* struct dirent **namelist */ /* block scope doesn't work */
int n;

n = getFileNames(H5DIR, namelist); /* included from mylib.h */
freeFileNames(namelist, n); /* included from mylib.h */

return 0;
}


Thank you very much for your comments,
Dieter

Here's the actual code if needed. Although dirent.h is platform
specific, I think my question is relative to standard C.


The actual code is not needed, and is indeed off-topic. Your problem
has a great deal to do with how the function scandir(), which is
apparently from dirent.h, deals with pointers.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>

#define H5DIR "/home/stella/data/h5/rawTables"

int getFileNames(char *directory, struct dirent **namelist);
int freeFileNames(struct dirent **namelist, int entries);

struct dirent **namelist;


When you define this pointer a file scope, it has static storage
duration and is therefore initialized to NULL. When you define it
inside a function, it has automatic storage duration by default and it
not initialized at all.

int main(void)
{
int n;

n = getFileNames(H5DIR, namelist);
printf("%d\n",n);
err = freeFileNames(namelist, n);
if (err==0)
printf("There wasn't any files");
return 0;
}

int getFileNames(char *directory, struct dirent **namelist)
{
int n, i;

n = scandir(directory, &namelist, 0, alphasort);


[snip]

On the last line of code above, you pass a pointer to 'namelist'
(therefore a char ***) to scandir(). Presumably this function checks
whether the pointed-to char ** is NULL or not, and if it is NULL, it
allocates the necessary memory. And also presumably, if the
pointed-to char ** is not NULL, it assumes that it points to valid
memory and uses it. At the end you try to free a pointer that was not
allocated.

I would suggest that you study the documentation for the function
scandir() and see what the requirements are for that parameter.

Jack, I sincerely thank you for commenting.

NULL initialization was certainly an issue.

Dieter

I guess this is a scope issue for variable "namelist"
I suggest to change the function
int getFileName(char *,struct dirent ***);
and make necessary changes to code.
it may work fine

bcoz scandir i guess sets "struct dirent **" itself.
if its global all is fine, but local variables 0 its problem-same as
pass by value

thanks
-M.B
 
M

M.B

please chanmge function int getFileName(char *,struct dirent **);
to int getFileNames(char *,struct dirent ***) and make necessary
changes to code to accomodate this

its a pass by value v/s pass by reference issue
 
C

Chuck F.

Dieter said:
Jack said:
[snip]

On the last line of code above, you pass a pointer to
'namelist' (therefore a char ***) to scandir(). Presumably
this function checks whether the pointed-to char ** is NULL or
not, and if it is NULL, it allocates the necessary memory.
And also presumably, if the pointed-to char ** is not NULL, it
assumes that it points to valid memory and uses it. At the
end you try to free a pointer that was not allocated.

I would suggest that you study the documentation for the
function scandir() and see what the requirements are for that
parameter.

Jack, I sincerely thank you for commenting.

NULL initialization was certainly an issue.

All of which points out why we want queries to be topical. Once
you involve an unknown header (dirent) and an unknown function
(scandir) nobody can have any accurate idea what goes on. This is
why this whole thread should have been on a newsgroup dealing with
your system in the first place.

The fact that Jack could make an educated guess does not affect
this. His guess could well have been total nonsense, and could
have missed important factors. There is (in principle) noone here
to correct any mistakes.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
 
C

Chris Torek

struct dirent **namelist; /* file scope works */

int main(void)
{
/* struct dirent **namelist */ /* block scope doesn't work */
int n;

n = getFileNames(H5DIR, namelist); /* included from mylib.h */

This passes the *value* of the variable "namelist" to the function.
If namelist has block scope, the variable is also automatic, and hence
uninitialized, and hence contains garbage. If namelist has file
scope, the variable also has static duration and hence is
initialized to NULL.

In any case, getFileNames() cannot change the value stored in
the variable named "namelist" (unless it does not declare one
of its own, and does access the file-scope one). So it makes
no sense to pass the value in the first place, if namelist is
a block-scope variable.

If getFileNames() needs to modify namelist, it will need the
address of the variable:

extern int getFileNames(first_type, struct dirent ***);
...
int main(void) {
struct dirent **namelist;
int n;

/* optional: namelist = NULL; */
n = getFileNames(H5DIR, &namelist);
freeFileNames(namelist, n); /* included from mylib.h */

Presumably the NULL-initialized file-scope static-duration version
causes freeFileNames() to be a no-op. Passing the uninitialized
value of the block-scope version presumably does not.
 
M

M.B

sorry if thjis is a duplicate reply...

I guess this is a scope issue for variable "namelist"
I suggest to change the function
int getFileName(char *,struct dirent ***);
and make necessary changes to code.
it may work fine

bcoz scandir i guess sets "struct dirent **" itself.
if its global all is fine, but local variables 0 its problem-same as
pass by value

thanks
-M.B
 
M

M.B

please check
pass by value
v/s pass by ref/pointers carefully


hope this helps to solve the issue
 
M

M.B

This works without segfault.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>

#define H5DIR "./"

int getFileNames(char *directory, struct dirent ***namelist);
int freeFileNames(struct dirent **namelist, int entries);


int main(void)
{
int n,err;
struct dirent **namelist;

n = getFileNames(H5DIR,&namelist);
printf("%d\n",n);
err = freeFileNames(namelist, n);
if (err==0)
printf("There wasn't any files");
return 0;

}

int getFileNames(char *directory, struct dirent ***namelist)
{
int n, i;

n = scandir(directory, namelist, 0, alphasort);
if(n == -1){
perror("scandir returned: ");
exit(1);
}
if(n == 0){
printf("No files found. Quiting.\n\n");
exit(1);
}
for (i=0;i<n;i++){
printf("File: %s\n", (*namelist)->d_name);
}

return n;

}

int freeFileNames(struct dirent **namelist, int entries)
{
int i;

if (namelist == NULL)
return 0;
else{
printf("%d",entries);
for (i = 0; i < entries; i++){
free(namelist);
namelist = NULL;
printf("%d,", i);
}
puts("\n");
free(namelist);
namelist = NULL;
}

return 1;
}
 
D

Dieter

Chuck said:
Dieter said:
Jack said:
[snip]

On the last line of code above, you pass a pointer to
'namelist' (therefore a char ***) to scandir(). Presumably
this function checks whether the pointed-to char ** is NULL or
not, and if it is NULL, it allocates the necessary memory.
And also presumably, if the pointed-to char ** is not NULL, it
assumes that it points to valid memory and uses it. At the
end you try to free a pointer that was not allocated.

I would suggest that you study the documentation for the
function scandir() and see what the requirements are for that
parameter.


Jack, I sincerely thank you for commenting.

NULL initialization was certainly an issue.


All of which points out why we want queries to be topical. Once you
involve an unknown header (dirent) and an unknown function (scandir)
nobody can have any accurate idea what goes on. This is why this whole
thread should have been on a newsgroup dealing with your system in the
first place.

The fact that Jack could make an educated guess does not affect this.
His guess could well have been total nonsense, and could have missed
important factors. There is (in principle) noone here to correct any
mistakes.

Yes I appreciate that.

My question, I believed, was standard C specific and debated whether to
post it here. In the future *anything* including anything other than
standard C will be posted elsewhere.

Possibly the newsgroup's name could be changed to comp.lang.C.standard,
or some such. It might eliminate a small amount of the regular grief you
all encounter.

Regards,
Dieter
 
M

M.B

Chuck said:
Dieter said:
Jack said:
[snip]

On the last line of code above, you pass a pointer to
'namelist' (therefore a char ***) to scandir(). Presumably
this function checks whether the pointed-to char ** is NULL or
not, and if it is NULL, it allocates the necessary memory.
And also presumably, if the pointed-to char ** is not NULL, it
assumes that it points to valid memory and uses it. At the
end you try to free a pointer that was not allocated.
Jack, I sincerely thank you for commenting.

NULL initialization was certainly an issue.

All of which points out why we want queries to be topical. Once
you involve an unknown header (dirent) and an unknown function
(scandir) nobody can have any accurate idea what goes on. This is
why this whole thread should have been on a newsgroup dealing with
your system in the first place.
btw dirent or dirent.h is not alien. its of course not in ansi but in
posix (k&r also mentions it)
The fact that Jack could make an educated guess does not affect
this. His guess could well have been total nonsense, and could
have missed important factors. There is (in principle) noone here
to correct any mistakes.

I agree here. Anyone replying here want to help in any case. But we all
can help in giving suggestions but not spoonfeed. I may not know what
others know . knowlegde sharing is the idea here.
 
M

M.B

Chuck said:
Dieter said:
Jack said:
[snip]

On the last line of code above, you pass a pointer to
'namelist' (therefore a char ***) to scandir(). Presumably
this function checks whether the pointed-to char ** is NULL or
not, and if it is NULL, it allocates the necessary memory.
And also presumably, if the pointed-to char ** is not NULL, it
assumes that it points to valid memory and uses it. At the
end you try to free a pointer that was not allocated.
Jack, I sincerely thank you for commenting.

NULL initialization was certainly an issue.

All of which points out why we want queries to be topical. Once
you involve an unknown header (dirent) and an unknown function
(scandir) nobody can have any accurate idea what goes on. This is
why this whole thread should have been on a newsgroup dealing with
your system in the first place.
btw dirent or dirent.h is not alien. its of course not in ansi but in
posix (k&r also mentions it)
The fact that Jack could make an educated guess does not affect
this. His guess could well have been total nonsense, and could
have missed important factors. There is (in principle) noone here
to correct any mistakes.

I agree here. Anyone replying here want to help in any case. But we all
can help in giving suggestions but not spoonfeed. I may not know what
others know . knowlegde sharing is the idea here.
 
D

Dieter

Dieter said:
Hi.

In the snippet of code below, I'm trying to understand why when the

struct dirent ** namelist

is declared with "file" scope, I don't have a problem freeing the
allocated memory. But when the struct is declared in main (block scope)
it will segfault when passing namelist to freeFileNames().

Since this seems to be just a matter of my understanding scope and
pointer parameter passing better, I only included what thought to be
relevant code. I'll happily provide compilable code if deemed necessary.

Please see commented lines:


struct dirent **namelist; /* file scope works */

int main(void)
{
/* struct dirent **namelist */ /* block scope doesn't work */
int n;

n = getFileNames(H5DIR, namelist); /* included from mylib.h */
freeFileNames(namelist, n); /* included from mylib.h */

return 0;
}


Thank you very much for your comments,
Dieter

My apologies to the regulars for an OT inclusion related to the question.


< This Thread Closed >


Thanks,
Dieter
 
D

Dieter

Chris said:
This passes the *value* of the variable "namelist" to the function.
If namelist has block scope, the variable is also automatic, and hence
uninitialized, and hence contains garbage. If namelist has file
scope, the variable also has static duration and hence is
initialized to NULL.

In any case, getFileNames() cannot change the value stored in
the variable named "namelist" (unless it does not declare one
of its own, and does access the file-scope one). So it makes
no sense to pass the value in the first place, if namelist is
a block-scope variable.

If getFileNames() needs to modify namelist, it will need the
address of the variable:

extern int getFileNames(first_type, struct dirent ***);
...
int main(void) {
struct dirent **namelist;
int n;

/* optional: namelist = NULL; */
n = getFileNames(H5DIR, &namelist);




Presumably the NULL-initialized file-scope static-duration version
causes freeFileNames() to be a no-op. Passing the uninitialized
value of the block-scope version presumably does not.

You've hit the nail on the head. That's exactly what I've been having
trouble wrapping my mind around.

* Pass the address of the pointer in order to return it's value modified. *

The N indirection, dynamic allocation, and passing them has been
confusing me.


Thanks Chris
 
D

Dieter

M.B said:
This works without segfault.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>

#define H5DIR "./"

int getFileNames(char *directory, struct dirent ***namelist);
int freeFileNames(struct dirent **namelist, int entries);


int main(void)
{
int n,err;
struct dirent **namelist;

n = getFileNames(H5DIR,&namelist);
printf("%d\n",n);
err = freeFileNames(namelist, n);
if (err==0)
printf("There wasn't any files");
return 0;

}

int getFileNames(char *directory, struct dirent ***namelist)
{
int n, i;

n = scandir(directory, namelist, 0, alphasort);
if(n == -1){
perror("scandir returned: ");
exit(1);
}
if(n == 0){
printf("No files found. Quiting.\n\n");
exit(1);
}
for (i=0;i<n;i++){
printf("File: %s\n", (*namelist)->d_name);
}

return n;

}

int freeFileNames(struct dirent **namelist, int entries)
{
int i;

if (namelist == NULL)
return 0;
else{
printf("%d",entries);
for (i = 0; i < entries; i++){
free(namelist);
namelist = NULL;
printf("%d,", i);
}
puts("\n");
free(namelist);
namelist = NULL;
}

return 1;
}

MB, I can't express enough how much I appreciate your contribution.
Thank you for taking the time... and bending the sacred rules a little. :)
 
K

Keith Thompson

Chuck F. said:
Dieter said:
Jack said:
[snip]
On the last line of code above, you pass a pointer to
'namelist' (therefore a char ***) to scandir(). Presumably
this function checks whether the pointed-to char ** is NULL or
not, and if it is NULL, it allocates the necessary memory.
And also presumably, if the pointed-to char ** is not NULL, it
assumes that it points to valid memory and uses it. At the
end you try to free a pointer that was not allocated.
I would suggest that you study the documentation for the
function scandir() and see what the requirements are for that
parameter.
Jack, I sincerely thank you for commenting.
NULL initialization was certainly an issue.

All of which points out why we want queries to be topical. Once you
involve an unknown header (dirent) and an unknown function (scandir)
nobody can have any accurate idea what goes on. This is why this
whole thread should have been on a newsgroup dealing with your system
in the first place.

The fact that Jack could make an educated guess does not affect this.
His guess could well have been total nonsense, and could have missed
important factors. There is (in principle) noone here to correct any
mistakes.

In this case, there wasn't really any need to guess. The code causing
the problem was:

struct dirent **namelist;
int n;
n = getFileNames(H5DIR, namelist);

It might as well have been:

struct foo **bar;
int n;
n = bleeble(blah, bar);

Regardless of what struct dirent/struct foo is, and regardless of what
getFileNames() or bleeble() does with its arguments, passing an
uninitialized variable to a function is almost certainly an error.
(Come to think of it, drop the "almost".)
 
T

tmp123

Dieter said:
int getFileNames(char *directory, struct dirent **namelist)
{
int n, i;

n = scandir(directory, &namelist, 0, alphasort);


Hi,

As other groups members has remarked, the problem was in the call to
scandir (the program doesn't works if the variable is global and also
doesn't works if it is local. The only diference is how bad are the
effects).

I want only to remark two things about modify a function parameter:
a) The changes done to the value of a parameter will be always lost at
function return.
b) Change a parameter is under stylistic discussion (in particular, I
never do it. If necessary, I declare a local and init it with the
parameter value), and, who knows if allowed by standard. By example, a
SPARC CPU uses registers to pass parameters, so, the address of a
parameter is something that breaks to normal function prologs
(assembler code at start of fucntion).

In conclusion, any line of the kind "&parameter" must be carefully
reviewed.

Kind regards.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,005
Messages
2,570,264
Members
46,859
Latest member
HeidiAtkin

Latest Threads

Top