stack smashing

F

frank

Richard said:
char *pathName = malloc(strlen(theDir) + strlen("/") +
strlen(entry.d_name) + 1);
if(pathName != NULL)
{
sprintf(pathName, "%s/%s", theDir, entry.d_name);

If the malloc call succeeded, pathName is now guaranteed to be long
enough, no matter how long theDir and entry.d_name are (up to the upper
limit of size_t, anyway).

Ok, I see. This obviates the need to know a priori how big these have
to be. Let me ask something a little different. In
comp.unix.programmer, Jens Theoring writes the following about a similar
getdir function:

If I were to "redesign" the function I probably would have
getdir() take only the path argument and have it return a
pointer to the file list, with the modification that the
file list always ends in a NULL pointer to mark its end -
that way you don't have to also keep track of how many
elements it has. And then I'd supply a second function,
free_dir_list(), which receives the file list and free()'s
everything in it.

Does this sound like a good memory model for this type of thing?
 
S

Seebs

Nothing wrong expect what I can only see as deliberately provocative
snipping. The context (just one line above) was:

a = sizeof(float);

If Richard Heathfield had suggested that int was wrong and unsigned
long was the type to use, AT would quite likely have gone off on one
about absurd fears that floats might be longer than 32,767 bytes.
Since int is perfectly reasonable here, AT had to snip the context to
go off on one. The common thread here is that AT will go off on one
no matter what one says.

While in general this is true, I don't think I agree in this case.
It is quite possible for programs to change over time, and sooner or
later, the assignment to a is going to be twenty lines from the printf,
and it's going to change into a calculation of the expected size of a
gigantic matrix or something, and we're going to want to print the
size as %zu (or %lu).

Basically, in my experience, it's always been better to do it right even
when I'm *totally* sure it doesn't matter, because code has a disconcerting
way of surviving until my shortcuts matter.

-s
 
J

Jens Thoms Toerring

frank said:
Richard Heathfield wrote:
Ok, I see. This obviates the need to know a priori how big these have
to be. Let me ask something a little different. In
comp.unix.programmer, Jens Theoring writes the following about a similar
getdir function:
If I were to "redesign" the function I probably would have
getdir() take only the path argument and have it return a
pointer to the file list, with the modification that the
file list always ends in a NULL pointer to mark its end -
that way you don't have to also keep track of how many
elements it has. And then I'd supply a second function,
free_dir_list(), which receives the file list and free()'s
everything in it.
Does this sound like a good memory model for this type of thing?

Please keep in mind that this was not about your process_directory()
function posted here but a function getdir() by a different poster
(in c.u.p) with perhaps some rather different goals than your's.
Your function returns jut the count of files that have been found,
while the original getdir() function was meant to set up a list of
file names in a directory. So that functions declaration was (near-
ly)

int getdir( const char * path, char *** list );

while your process_directory() function has more or less

unsigned int getdir( const char * path );

Since your function doesn't return a list of file names the
whole thing is quite a bit different.

If you return an array from a function the basic question is:
do I need to keep track of the address of the array *and* the
number of it elements? If an array can't have an element that
tells 'this elememt is invalid and thus can signify the end of
the array' then you have no alternative to keeping track of the
array's address *and* the number of its arguments. But if you
have e.g. an array of pointers there are situations where a NULL
element can be used to indicate 'this is the last (and invalid)
element', and in that case you can use such an element as a
'sentential' (like the '\0' character at the end of a char array
is used to mark the end of a string).

Regards, Jens
 
S

steve

NVIDIA has proposed a new 16 bit floating point format
(used now internally in their GPUs).

Is there a problem with binary16 as defined in the
IEEE754 standard?
 
K

Keith Thompson

jacob navia said:
frank a écrit : [...]
It seems like floats have floated away. I can't think of a reason a
person would want a float as opposed to a double: anything that
float can represent is also represented by a double.

6.3.1.7 is a good place to read up on this.

Please, do not generalize too much. Float use 50% of the memory
needed by a double, and when memory is important and precision is not,
it is better to use float.
[...]

Speaking of generalizing too much:

float is *typically* half the size of double, but the only guarantee
is that double is no smaller than float (actually that it has at least
the same range and precision). I've worked on systems where float and
double were the same size.

Still your advice is correct most of the time and probably harmless
the rest of the time.
 
F

frank

Please keep in mind that this was not about your process_directory()
function posted here but a function getdir() by a different poster
(in c.u.p) with perhaps some rather different goals than your's.
Your function returns jut the count of files that have been found,
while the original getdir() function was meant to set up a list of
file names in a directory. So that functions declaration was (near-
ly)

int getdir( const char * path, char *** list );

while your process_directory() function has more or less

unsigned int getdir( const char * path );

Since your function doesn't return a list of file names the
whole thing is quite a bit different.

It was my first try, mostly borrowed from something I found while
googling. It seems to me that your ideas that you had for someone
else in c.u.p. were closer to what I'm looking to do.
If you return an array from a function the basic question is:
do I need to keep track of the address of the array *and* the
number of it elements? If an array can't have an element that
tells 'this elememt is invalid and thus can signify the end of
the array' then you have no alternative to keeping track of the
array's address *and* the number of its arguments. But if you
have e.g. an array of pointers there are situations where a NULL
element can be used to indicate 'this is the last (and invalid)
element', and in that case you can use such an element as a
'sentential' (like the '\0' character at the end of a char array
is used to mark the end of a string).

Ok. Well this had been a big problem for me when I was declaring
things from a caller. I'll need to make a mock-up in standard c with
a similar function like getText, where the items are returned in a
list.

For the getDir function that you envision, is this an appropriate
declaration:

char * getDir( char * pathName);

"Sentinel" seems to be a word that non-native English writers struggle
with. It means something like "guard." I delivered the "sentinel
tribune" growing up, as a paperboy, which might be a job that doesn't
exist anymore.

Gruss aus Amiland,
 
F

frank

Please keep in mind that this was not about your process_directory()
function posted here but a function getdir() by a different poster
(in c.u.p) with perhaps some rather different goals than your's.
Your function returns jut the count of files that have been found,
while the original getdir() function was meant to set up a list of
file names in a directory. So that functions declaration was (near-
ly)

int getdir( const char * path, char *** list );

while your process_directory() function has more or less

unsigned int getdir( const char * path );

Since your function doesn't return a list of file names the
whole thing is quite a bit different.

It was my first try, mostly borrowed from something I found while
googling. It seems to me that your ideas that you had for someone
else in c.u.p. were closer to what I'm looking to do.
If you return an array from a function the basic question is:
do I need to keep track of the address of the array *and* the
number of it elements? If an array can't have an element that
tells 'this elememt is invalid and thus can signify the end of
the array' then you have no alternative to keeping track of the
array's address *and* the number of its arguments. But if you
have e.g. an array of pointers there are situations where a NULL
element can be used to indicate 'this is the last (and invalid)
element', and in that case you can use such an element as a
'sentential' (like the '\0' character at the end of a char array
is used to mark the end of a string).

Ok. Well this had been a big problem for me when I was declaring
things from a caller. I'll need to make a mock-up in standard c with
a similar function like getText, where the items are returned in a
list.

For the getDir function that you envision, is this an appropriate
declaration:

char * getDir( char * pathName);

"Sentinel" seems to be a word that non-native English writers struggle
with. It means something like "guard." I delivered the "sentinel
tribune" growing up, as a paperboy, which might be a job that doesn't
exist anymore.

Gruss aus Amiland,
 
S

Seebs


I think the issue is that an uncharitable or hostile reader might ignore
the qualifier or misunderstand it. I assumed that the qualifier meant
exactly what it said; if you need to pass something so that it will print with
%d, cast it to int. I didn't infer any particular assertion as to whether
or not trying to print sizes with %d was a good idea; merely an observation
about how one would go about it.
Also right. Unfortunately, it isn't possible to give an entirely
comprehensive response to every single article. We take shortcuts,
either through time pressure or through simple humanness. Sometimes we
take shortcuts that seem reasonable to some observers but not to others.
And sometimes the opinion of an observer on whether the shortcut is a
reasonable one will depend on his opinion of the shortcutter.

Yes. In this case, I think, a reasonable reader familiar with your
background would not imagine that you were suggesting that %d was the
right choice for printing a size, but a hostile reader might choose to
read it that way to try to score points.

-s
 
M

Michael Foukarakis

C does not define the behaviour of a program whose behaviour is
undefined. So any result is okay, including the Wiki's result and any
other result (or no result at all).

Puh-lease. :) If only that were true, then exploits would fail half
the time, only because stack smashing invokes UB. Heh.

OP, compile the example with -fno-stack-protector and/or -
D_FORTIFY_SOURCE=0. You will get your desired result then. Read up on
stack canaries and GCC's stack protection schemes to understand why
your current setup fails (there's code that detects you've overwritten
something on the stack and produces the "*** stack smashing detected
***" message along with the diagnostic backtrace/mmap).
 
J

Jens Thoms Toerring

frank said:
For the getDir function that you envision, is this an appropriate
declaration:
char * getDir( char * pathName);

Nearly - but since it's supposed to return an array of strings
it has to be

char ** getDir( char * pathName);

And I probably would throw in a 'const' before 'char * pathName'
if the function doesn't change that string.
"Sentinel" seems to be a word that non-native English writers struggle
with.

At least at half past two in the morning;-)

Regards, Jens
 
N

Nick Keighley

if you read the documentation for strncpy() you will it is rather odd.
strcpy() is designed for copying small fixed arrays of characters that
were not necessarily zero terminated. I believe unix has (or had) such
things.

char thing_name[8] = "AAAABBBB";
the above is not nul terminated in C (C++ is different) becasue the
number of characters in the initialiser exactly fits.

strncpy (thing_name, "NEW_NAME", 8);
copies eactly 8 characters. No null on the end.

strncpy (thing_name, "SMALL", 8);
copies 5 character and appends three nuls.

This all makes sense but it often isn't what people expect. The strncpy
() of "NEW_NAME" means that thing_name isn't a valid C string after
the call! There's no terminator. And that padding habbit can go wildly
wrong.

char buffer[100];
strncpy (buffer, "tmp/", 100);

avoids a call of strlen() on "tmp/" (saving 5 character reads) but
tags 96 nuls onto the end of buffer.

One possibility is to write a function that does what you might expect
strncpy() to do. (but don't call it str*() because that invades a
namespace reserved for the implementation).
In this case, malloc (to build a sufficiently long buffer), followed by
a check to ensure it succeeded, followed either by error handling or
sprintf.

(I was going to post code, but Richard has done it else-thread)
 
J

jacob navia

Jens Thoms Toerring a écrit :
If you return an array from a function the basic question is:
do I need to keep track of the address of the array *and* the
number of it elements? If an array can't have an element that
tells 'this elememt is invalid and thus can signify the end of
the array' then you have no alternative to keeping track of the
array's address *and* the number of its arguments. But if you
have e.g. an array of pointers there are situations where a NULL
element can be used to indicate 'this is the last (and invalid)
element', and in that case you can use such an element as a
'sentential' (like the '\0' character at the end of a char array
is used to mark the end of a string).

Regards, Jens

And here we see (AGAIN) how useful would be to have in C a
standard array container that can be used in situations like this!

That is one of the principal motivations of the containers library.

jacob
 
J

jacob navia

steve a écrit :
Is there a problem with binary16 as defined in the
IEEE754 standard?

No, I think the 16 bit float corresponds to some IEEE754
type. I researched this a while ago but I do not have the details
right now.

The next pentium generation will have those built in, that is why
I researched that.
 
M

Michael Foukarakis

Ok, I see.  This obviates the need to know a priori how big these have
to be.  Let me ask something a little different.  In
comp.unix.programmer, Jens Theoring writes the following about a similar
getdir function:

If I were to "redesign" the function I probably would have
getdir() take only the path argument and have it return a
pointer to the file list, with the modification that the
file list always ends in a NULL pointer to mark its end -
that way you don't have to also keep track of how many
elements it has. And then I'd supply a second function,
free_dir_list(), which receives the file list and free()'s
everything in it.

Does this sound like a good memory model for this type of thing?

It does. When using/building containers, you have two ways of
signifying the end of data; either a sentinel value that denotes the
end of available items (like NULL, or whatever) or a value that tells
you the "length" or "size" of your container. Both are perfectly
acceptable, with their own sets of problems. :)
 
J

John Bode

As usual you are completely wrong Twink. Why dont you FOD?- Hide quoted text -

- Show quoted text -

Twink's not wrong. For *this specific case*, it's highly unlikely
that the length of the string will exceed the maximum value for a
signed integer, but in general it's best to treat size_t values as
unsigned, potentially longer than int.

Note that Heathfield included the caveat "If you want to pass a size_t
to printf to match a %d format specifier," so his advice was correct
as far as it went, however I think the OP would have been better
served if Heathfield had given the same advice Twink gave (minus the
personal animosity towards the larger clc community): i.e., use "%lu"
and cast to unsigned long in C89, use %zu in C90.
 
K

Keith Thompson

Michael Foukarakis said:
Puh-lease. :) If only that were true, then exploits would fail half
the time, only because stack smashing invokes UB. Heh.

Ah, but it is true. Any result is okay in the sense that it's
permitted by the standard. That includes getting consistent results
on a particular system, which is what exploits generally take
advantage of.

[...]
 
J

John Bode

Twink's not wrong.  For *this specific case*, it's highly unlikely
that the

size of type float
will exceed the maximum value for a
signed integer, but in general it's best to treat size_t values as
unsigned, potentially longer than int.

Fixed because I'm a moron who doesn't always pay attention to what
he's responding to.
 
A

Antoninus Twink


Read again.

I never said that your advice was incorrect. I said it was exceptionally
poor advice.

Consider this example:

"Q: Why do I get a compiler warning for this code?
const char *s;
gets(s);
A: You need to remove the const qualifier if you want to pass s to gets()."

Perfectly correct advice, but also exceptionally poor advice.
We take shortcuts, either through time pressure or through simple
humanness. Sometimes we take shortcuts that seem reasonable to some
observers but not to others.

Yes, an most people by instinct make allowances for this perfectly
normal part of human nature.

You, on the other hand, have made a career out of humiliating newbies
and pissing off old hands by an excessively literal reading of their
posts and a refusal to read between the lines in exactly the way you
describe.

I'm happy to be able to give you a taste of your own medicine once in a
while.
 
A

Antoninus Twink

I think the issue is that an uncharitable or hostile reader might ignore
the qualifier or misunderstand it.

Yes - and the very person who delights in being an uncharitable or
hostile reader when others are writing is none other than one Dicky
Heathfield.
 

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
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top