segfault w/ block, but not file scope

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.
 
R

Richard Heathfield

M.B said:
its a pass by value v/s pass by reference issue

Since C doesn't have pass by reference, it is clear to me that you are
talking nonsense.
 
M

M.B

Keith said:
Chuck F. said:
Dieter said:
Jack Klein wrote:
[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".)

Why do we initialize the variable if the variable is it is being
returned by the called function with a valid value
for ex
void f(int *i)
{
*i=1;
return;
}

int main(void)
{
int k; /*why need int k=0... */
f(&k);
...
return(0);
}
------------------
related
----------------------
void f(int i) /* I intend to modify i */
{
i=1;
return;
}

int main(void)
{
int k=0; /*why need int k=0... */
f(k);
...
return(0);
}

No effect on variable "k"
what initialization (0) helps in this case


- M.B
 
D

Dieter

tmp123 said:
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),

Hi tmp,

Hmm, this last point you made is not quite clear to me. My goal is to
try to localize/modularize most of what I can and dynamic
allocation~value passing will also be necessarily frequent (I think)
considering event driven considerations. I don't see how I'd be able to
avoid it.

Thanks for your commenting,
Dieter

and, who knows if allowed by standard. By example, a
 
M

M.B

Richard said:
M.B said:


Since C doesn't have pass by reference, it is clear to me that you are
talking nonsense.
I presume u area c++ guy to talk like this.
pass by reference is a generic term for ur info.
C iimplements this by pointers.

- M.B
 
C

Chuck F.

M.B said:
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

Please use English, not dudespeak, in this newsgroup, and include
adequate context. Between the two your article is totally
meaningless. See below for further advice.

--
"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/>
 
T

tmp123

Dieter said:
Hi tmp,

Hmm, this last point you made is not quite clear to me. My goal is to
try to localize/modularize most of what I can and dynamic
allocation~value passing will also be necessarily frequent (I think)
considering event driven considerations. I don't see how I'd be able to
avoid it.

Thanks for your commenting,
Dieter

and, who knows if allowed by standard. By example, a


Sorry, it is my fault, I've not been clear enough:

Some examples:

void foo(int *a)
{
*a=14;
}

void test ( int a )
{
int b;
b=2; /* 1: of course, OK */
a=2; /* 2: probably OK, but I do not know if according statndard, and
only in my personal style, not nice */
foo(&b); /* 3: OK */
foo(&a); /* 4: same than 2. In additon, dangerous in the sense that
it is
easy to thing that "a" will be modified afetr
return. Moreover, in some
machines "a" is stored in a register, so, &a
causes an small dificulty */
}

Is point 4 the one that, I do not say wrong, but I suggest to verify
carefully. In fact, one line like this one is the origin of the problem
in your post.

Kind regards.
 
M

M.B

Chuck said:
Please use English, not dudespeak, in this newsgroup, and include
adequate context. Between the two your article is totally
meaningless. See below for further advice.

For letting out context, my mistake sorry.
English - hope this is not an english literature group. People want
answers and its enough if they get those in anyway. go hell with
correct English.

Also please check if the advice given in your signature works
correctly.

And finally, noone has time and patience to reply to trolls.
 
M

M.B

tmp123 said:
Sorry, it is my fault, I've not been clear enough:

Some examples:

void foo(int *a)
{
*a=14;
}

void test ( int a )
{
int b;
b=2; /* 1: of course, OK */
a=2; /* 2: probably OK, but I do not know if according statndard, and
only in my personal style, not nice */
foo(&b); /* 3: OK */
foo(&a); /* 4: same than 2. In additon, dangerous in the sense that
it is

Sorry if i did'nt get you
But why would anyone ever write such a construct
In this case "a" could as well be a local var in test
bcoz after return from test (to main or somewhere) anyway parameter to
test remains unchanged
 
R

Randy Howard

M.B wrote
(in article
btw dirent or dirent.h is not alien. its of course not in ansi but in
posix (k&r also mentions it)

It most certainly is alien to those not using a POSIX platform,
and IIRC, it pre-dates POSIX. Even so, there is no guarantee
that a standard conforming C compiler and linker will no a thing
about it. That's the whole point.
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.

No, the issue raised was that if someone asks a question about a
nonstandard extension that is rarely seen, or at least not by
the regulars, then any responses offered could be complete
bullschildt, yet go undetected. When you ask a question in a
forum populated by people that specialize on the topic, you get
much better (and peer reviewed) answers. When you ask a
question on GPS navigation in comp.graphics.apps.photoshop, no
telling what will happen.
 
M

M.B

Randy said:
M.B wrote
(in article


It most certainly is alien to those not using a POSIX platform,
and IIRC, it pre-dates POSIX. Even so, there is no guarantee
that a standard conforming C compiler and linker will no a thing
about it. That's the whole point.


No, the issue raised was that if someone asks a question about a
nonstandard extension that is rarely seen, or at least not by
the regulars, then any responses offered could be complete
bullschildt, yet go undetected. When you ask a question in a
forum populated by people that specialize on the topic, you get
much better (and peer reviewed) answers. When you ask a
question on GPS navigation in comp.graphics.apps.photoshop, no
telling what will happen.
I agree to some extend, but the question is whether we can push off any
queries just because they stray slightly in to an area beyond the group
topic (is this a sacred line ?).
in any case the problem here was not due to use of any non standard
functions etc (just that it was part of the code).
 
J

Jordan Abel

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.

scandir(const char *dirname, struct dirent ***namelist, int
(*select)(struct dirent *), int (*compar)(const void *, const void *));

According to the the manpage, it appears to build an array of pointer to
struct dirent, the with the array of pointers and the object pointed to
by each pointer being from malloc(). It then stores the "array" [i.e.
first level of malloc pointer] in *namelist.
#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.

My understanding of the manpage on my implementation, backed up by my
reading of the source on my particular implementation, is that it
ignores any previously-pointed-to value and only stores to *namelist.

[why are you calling 'struct dirent' 'char'?]
At the end you try to free a pointer that was not allocated.

You snipped this part, so I can't comment on it. According to the
manpage, you are supposed to free each member of *namelist [individual
struct dirent *] in turn, then free *namelist. The question is, what
differs between his two versions?
 
J

Jordan Abel

M.B said:


Since C doesn't have pass by reference, it is clear to me that you are
talking nonsense.

"pass by reference", in common usage, can also apply to the practice
(common in C and appearing several places in the standard library) of
passing a pointer to a value intended to be stored into, rather than any
alternate calling convention specifically supported by the language
 
K

Keith Thompson

M.B said:
Keith Thompson wrote: [...]
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".)

Why do we initialize the variable if the variable is it is being
returned by the called function with a valid value

Because evaluating an uninitialized variable, whether by using it as a
function argument or in some other expression, invokes undefined
behavior.
for ex
void f(int *i)
{
*i=1;
return;
}

int main(void)
{
int k; /*why need int k=0... */
f(&k);
...
return(0);
}

That's not the same thing. There's no need to initialize k, because
you're not passing the value of k to f(); you're merely passing its
address. Within f(), the value of *i is uninitialized garbage, but
that's ok because it doesn't attempt to read it. The value of i is a
valid address (specifically the address of main's k), so there's no
problem referring to i.
------------------
related
----------------------
void f(int i) /* I intend to modify i */
{
i=1;
return;
}

int main(void)
{
int k=0; /*why need int k=0... */
f(k);
...
return(0);
}

No effect on variable "k"
what initialization (0) helps in this case

This f() function is very strangely written. The first thing it does
is assign a value to its parameter, losing whatever value was passed
in by the caller. It would make more sense to declare "void f(void)"
and make i a local variable.

For a realistic function f() that uses the value of its parameter, it
wouldn't make sense to call it with an uninitialized value. Even with
f() as written, if you changed "int k=0;" to "int k;", just evaluating
the value of k invokes undefined behavior. In practice, this is
unlikely to cause any visible symptoms; type int typically doesn't
have any trap representations. You are likely, however, to get a
warning from the compiler.

When you post a followup, please delete any quoted text that isn't
relevant. In particular, don't quote a signature unless you're
actually commenting on the signature. (Deletions are typically marked
with "[...]" or "[snip]".)
 
K

Keith Thompson

tmp123 said:
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).

The variable in question was a pointer which is passed to a function.
If it's global, it's initialized to a null pointer value, which could
be a perfectly valid value for that argument. Whether this is
actually the case depends on the details of the non-standard function
scandir().
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.

A parameter is effectively a local variable, initialized to the value
given in the call. Taking its address is no more problematic that
taking the address of any other local variable. The fact that it may
have been passed in a register is irrelevant; if you take and use its
address, the compiler *must* store it in memory somewhere.

I tend to agree with you about the style issue of not modifying the
value of a parameter within a function. If I see a reference to a
parameter within a function, I tend to assume that it refers to the
value that was passed by the caller; if the function modifies it,
understanding the function requires a more complex mental model. But
this is at least partly because I've spent a lot of time working in a
language that makes parameters constant by default; I think that was a
good idea from a language design point of view, but it's not what C
does. In C, as I said, a parameter is really just a local variable,
and as a *reader* of C you have to be prepared to deal with code that
treats it as a variable.
 
D

Dieter

Keith said:
The variable in question was a pointer which is passed to a function.
If it's global, it's initialized to a null pointer value, which could
be a perfectly valid value for that argument. Whether this is
actually the case depends on the details of the non-standard function
scandir().




A parameter is effectively a local variable, initialized to the value
given in the call. Taking its address is no more problematic that
taking the address of any other local variable. The fact that it may
have been passed in a register is irrelevant; if you take and use its
address, the compiler *must* store it in memory somewhere.

I tend to agree with you about the style issue of not modifying the
value of a parameter within a function. If I see a reference to a
parameter within a function, I tend to assume that it refers to the
value that was passed by the caller; if the function modifies it,
understanding the function requires a more complex mental model. But
this is at least partly because I've spent a lot of time working in a
language that makes parameters constant by default; I think that was a
good idea from a language design point of view, but it's not what C
does. In C, as I said, a parameter is really just a local variable,
and as a *reader* of C you have to be prepared to deal with code that
treats it as a variable.

Hi Kieth, thank you for your comments.

So if I understand correctly, It's advisable, that when passing a
pointer in the paramater of a called function (that needs to be modified
for the originating (calling) scope, /for example/ ), that the paramater
(passed pointer) should then be pointed to by a local pointer variable
in the called function. This then makes *clear* the individuality
between the original value being passed and the modification of that
value, and is then,in effect, modifying the value in the calling scope.

Dieter
 
K

Keith Thompson

Dieter said:
Keith Thompson wrote: [...]
A parameter is effectively a local variable, initialized to the value
given in the call. Taking its address is no more problematic that
taking the address of any other local variable. The fact that it may
have been passed in a register is irrelevant; if you take and use its
address, the compiler *must* store it in memory somewhere.
I tend to agree with you about the style issue of not modifying the
value of a parameter within a function. If I see a reference to a
parameter within a function, I tend to assume that it refers to the
value that was passed by the caller; if the function modifies it,
understanding the function requires a more complex mental model. But
this is at least partly because I've spent a lot of time working in a
language that makes parameters constant by default; I think that was a
good idea from a language design point of view, but it's not what C
does. In C, as I said, a parameter is really just a local variable,
and as a *reader* of C you have to be prepared to deal with code that
treats it as a variable.

Hi Kieth, thank you for your comments.

It's "Keith".
So if I understand correctly, It's advisable, that when passing a
pointer in the paramater of a called function (that needs to be
modified for the originating (calling) scope, /for example/ ), that
the paramater (passed pointer) should then be pointed to by a local
pointer variable in the called function. This then makes *clear* the
individuality between the original value being passed and the
modification of that value, and is then,in effect, modifying the value
in the calling scope.

Um, no. I wasn't talking about pointers at all.

C doesn't directly implement pass-by-reference, so it's emulated by
passing a pointer (the pointer itself is, of course, passed by value).

For example:

#include <stdio.h>

static void increment(int *ptr)
{
*ptr ++;
}

int main(void)
{
int i = 42;
increment(&i);
printf("i = %d\n", i);
return 0;
}

Since ptr itself is never modified, the style issue I discussed above
doesn't arise. There would be no advantage stylistic or otherwise, in
making a local copy of ptr within the increment() function.

The case I was talking about was something more like this:

#include <stdio.h>

static void count_to_ten(int n)
{
while (n <= 10) {
printf("%d\n", n);
n++;
}
}

int main(void)
{
count_to_ten(5);
return 0;
}

Here the count_to_ten() function modifies the value of its parameter
(which obviously can have no effect on the caller). Some might
consider it poor style to the parameter like this, since it's natural
to think of n as the value that was passed in. But there's nothing
*really* wrong with it; n is just a local variable, and it's perfectly
legal to modify it. But in a more complex function, you might want to
look at the *original* value of n that was passed in; modifying n
makes this impossible. The problem can be avoided by copying n to
another local variable, and leaving the parameter value alone.

Either approach is acceptable, but some people are a bit uneasy about
modifying parameters.
 
D

Dieter

Keith said:
Dieter said:
Keith Thompson wrote:
[...]
A parameter is effectively a local variable, initialized to the value
given in the call. Taking its address is no more problematic that
taking the address of any other local variable. The fact that it may
have been passed in a register is irrelevant; if you take and use its
address, the compiler *must* store it in memory somewhere.
I tend to agree with you about the style issue of not modifying the
value of a parameter within a function. If I see a reference to a
parameter within a function, I tend to assume that it refers to the
value that was passed by the caller; if the function modifies it,
understanding the function requires a more complex mental model. But
this is at least partly because I've spent a lot of time working in a
language that makes parameters constant by default; I think that was a
good idea from a language design point of view, but it's not what C
does. In C, as I said, a parameter is really just a local variable,
and as a *reader* of C you have to be prepared to deal with code that
treats it as a variable.

Hi Kieth, thank you for your comments.


It's "Keith".

Oops, sorry about that, my fingers are accustomed to "ie" /Dieter/
Um, no. I wasn't talking about pointers at all.

C doesn't directly implement pass-by-reference, so it's emulated by
passing a pointer (the pointer itself is, of course, passed by value).

For example:

#include <stdio.h>

static void increment(int *ptr)
{
*ptr ++;
}

int main(void)
{
int i = 42;
increment(&i);
printf("i = %d\n", i);
return 0;
}

Since ptr itself is never modified, the style issue I discussed above
doesn't arise. There would be no advantage stylistic or otherwise, in
making a local copy of ptr within the increment() function.

The case I was talking about was something more like this:

#include <stdio.h>

static void count_to_ten(int n)
{
while (n <= 10) {
printf("%d\n", n);
n++;
}
}

int main(void)
{
count_to_ten(5);
return 0;
}

Here the count_to_ten() function modifies the value of its parameter
(which obviously can have no effect on the caller). Some might
consider it poor style to the parameter like this, since it's natural
to think of n as the value that was passed in. But there's nothing
*really* wrong with it; n is just a local variable, and it's perfectly
legal to modify it. But in a more complex function, you might want to
look at the *original* value of n that was passed in; modifying n
makes this impossible. The problem can be avoided by copying n to
another local variable, and leaving the parameter value alone.

Either approach is acceptable, but some people are a bit uneasy about
modifying parameters.

I thank you sincerely and yes that makes perfect sense. :)

Dieter
 
C

Chris Torek

C doesn't directly implement pass-by-reference, so it's emulated by
passing a pointer (the pointer itself is, of course, passed by value).

For example:

#include <stdio.h>

static void increment(int *ptr)
{
*ptr ++;
}

Your example is somewhat marred by missing parentheses, or a
misplaced operator -- you mean:

++*ptr;

or

(*ptr)++;

[snippage]
The case I was talking about was something more like this:

#include <stdio.h>

static void count_to_ten(int n)
{
while (n <= 10) {
printf("%d\n", n);
n++;
}
} [snippage]
Here the count_to_ten() function modifies the value of its parameter
(which obviously can have no effect on the caller). Some might
consider it poor style to the parameter like this, since it's natural
to think of n as the value that was passed in.

I think this is fine, myself; but it is true that some prefer to
write:

static void count_to_ten(const int n0) {
int n = n0;
while (n <= 10) ...
}

Some (but not all) of these folks use the "const" qualifier, as shown
above, to make sure they do not accidentally modify n0.

I will take this opportunity to note that, in functions that do
deliberately modify a parameter, I tend to declare a local that is
one level "less pointer-y". For instance, in the code at the
start of this thread, I might write the routine that calls
scandir() as:

int somefunc(const char *dir, struct dirent ***anamelist) {
struct dirent **namelist;
int i, n;

n = scandir(dir, &namelist, NULL, NULL);
if (n == -1) ... handle error ...
for (i = 0; i < n; i++)
... work with namelist ...
...
*anamelist = namelist; /* set extra return value */
return n; /* and return "main" return value */
}

This avoids the need to write (*anamelist) everywhere that "namelist"
appears. Of course &(*anamelist) simplifies to anamelist, so the
scandir call itself is no simpler; but the contents of the "for"
loop -- where we work with namelist->field instead of
(*anamelist)->field -- are much easier to read.

There is no particular reason to defer updating *anamelist until
the end of the function, but no particular reason to do it earlier,
either.
 
K

Keith Thompson

Chris Torek said:
Your example is somewhat marred by missing parentheses, or a
misplaced operator -- you mean:

++*ptr;

or

(*ptr)++;

D'oh! Thanks for catching that. (I did compile and run it; I just
missed the fact that the output was "i = 42" rather than the intended
"i = 43".)
 

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,006
Messages
2,570,265
Members
46,861
Latest member
SanoraS48

Latest Threads

Top