x86 binary runs; x86_64 binary throws segfault

P

Paul N

No doubt it will now be picked apart for some horrible error or its
style. ;-)
        memcpy(copy, s, strlen(s)+1);  

Wouldn't "strcpy(copy, s)" be quicker (no need to search through
twice), less error-prone (won't forget the "+1") and more readable
(says what is intended)?
 
M

Mark

Paul N said:
Wouldn't "strcpy(copy, s)" be quicker (no need to search through
twice), less error-prone (won't forget the "+1") and more readable
(says what is intended)?

Yes, but I'm allergic to strcpy. ;-)
 
L

lawrence.jones

Don said:
Indeed; it's shockingly bad, bad enough that even I can see it's bad.
It does work, of course,

Only by accident. It's behavior is completely undefined -- it could do
*anything* (including appearing to work, which seems to be the behavior
you're seeing).
but much better would be i=i+1.

Or just ++i or i++. For what it's worth, most C programmers choose i++
when they don't care one way or the other.
 
E

Eric Sosman

[...] If someone runs the
program with no non-'-' command-line arguments, this test takes
you to Never-Never Land because you're trying to inspect a pointer
that isn't in the argv array, has no defined value, and may
not even exist!

Is it possible to run a program with no non-'-' arguments? The
program name will always be there, won't it? Of course, I see that I
skip over that anyway with the initial ++argv in the while loop.

Yes, the program name will always be there (it might be the
empty string "" if no name can be determined), but suppose
that's the *only* thing that's there. Then the *++argv in the
first loop will find the NULL at the end of the two-place array
{name, NULL}, and the *++argv in the next test will walk right
off the end.
I suppose I should just test it "if (*(argv) == NULL)" then?

That would work: "Look before you leap." An alternative
would be to use the argc value, which tells you the total
number of command-line arguments.
A simpler test for "Is there anything after the semicolon?"
is to ask whether the next character is the end-of-string '\0'
or is something else: `if (s[endpoint+1] != '\0')'.

Much simpler, no function call overhead. Fixed.

It's not about the overhead: Even though there is some, it
is likely[*] to be so tiny as to be difficult to measure. The
real improvement comes from the better expression of intent:
You really don't care about the length of the string, but about
whether the string continues or doesn't continue beyond the
semicolon -- so write your test that way. Don't weigh the car
to find out how many passengers are in it; look through the
window.

[*] I once had the experience of working on a machine where
the overhead was LARGE and could not be neglected. Is it any
wonder that the maker of that machine is no longer in business?
There can't be, as I understand it, because that would mean much more
precision than the data type can handle. I'll write in error checking
on it later.

Take your own route, do what works for you. In close to
forty years of writing programs in dozens of languages, it's
always -- always! -- seemed to me that handling the exceptional
cases is best thought about first, not last. One big reason
is that it's not enough just to detect a strangeness: You must
also choose how to respond to it. That choice may have profound
effects on the overall program structure and on the definitions
of your functions/subroutines/lambdas/methods, and is the sort
of thing that's hard to "stick on" at the end.
Yes; I should pad it with zeroes, and will do so.

Ah, but is there enough room in the string? Those command-
line arguments, for example: If one of them is "12;3e7" you can
only be sure of seven characters (including the '\0'). If you
try to store the eleven characters of "123000000;" into the
space that suffices for seven, ...
Ha; I actually thought of that one. :) They're padded on the left
with zeroes, and then semicolon inserted later. That's what


is for. I'm not sure if this actually works (in fact, looking at it I
think it doesn't), but that's what I was going for. I'll test it out
tonight.

I was running out of steam when I got to that loop, and didn't
look at it closely (still haven't). But again: How do you know
there's enough room for all those zeroes? The seven characters
of "12;e-7" won't hold the nine characters of ";0000012".
It is; I'm looking for the maximum possible accuracy. Eliminating all
those small inaccuracies is something I'm very interested in.

Okay. A full-scale job that squeezes the last little bit of
accuracy out of the conversion is, to coin a phrase, "non-trivial."
Pointless initialization: The initial value will never be
used, so you might as well initialize to `-2.71828'. Or to
nothing. As it is, specifying an initial value fools the reader
into thinking that the value is important -- when in fact it is
completely UNimportant.

Well, divisor *has* to start at 1.0, doesn't it? [...]

Sorry if I was unclear: This comment was aimed only at the
single line that preceded it. Yes, divisor's value is used --
but fracval's is not, and that's the useless initialization.
 
B

Ben Bacarisse

Don said:
The string in zensuf is not null terminated.  You stop when "see" the
null but you never put it into the array.
   exp = doztodec(zensuf);

This call expects a proper string -- one [that] is null terminated.
So all I need to do to fix this bizarre problem about the second call,
and only the second call, failing when every other call, even with the
same input, succeeds is null terminate the string?

I don't know for sure. It's a start. I'd be surprised it that is all
you need to fix. I only had a moment so I just wanted indicate what
the problem was.

Most people are quite friendly here, so don't be afraid to post again
if you want the code to be looked over once you have done what you
feel you can.
 
M

Mark

Richard Heathfield said:
Why so? Are you one of these who has been scared off strcpy? It's a
cargo cult thing. There's nothing wrong with strcpy that can be fixed
with strncpy.

I normally go with strncpy - I chose went with memcpy for no particular
reason. It's strcpy I have problems with - for obvious reasons.
 
S

Seebs

I normally go with strncpy - I chose went with memcpy for no particular
reason. It's strcpy I have problems with - for obvious reasons.

What are those obvious reasons?

I can't think of anything specific that would make me use memcpy instead
of strcpy for data that's intended to be a string.

-s
 
M

Mark

Seebs said:
What are those obvious reasons?

I can't think of anything specific that would make me use memcpy instead
of strcpy for data that's intended to be a string.

Nah - I'm being stupid.
 
M

Mark

Richard Heathfield said:
Perhaps you misread what I wrote. There's nothing wrong with strcpy that
can be fixed with strncpy. Why use strncpy, then? It offers no
advantages and one or two disadvantages.


They're not obvious to me.

See my reply to Seebs. ;-)
 
K

Keith Thompson

Mark said:
I normally go with strncpy - I chose went with memcpy for no particular
reason. It's strcpy I have problems with - for obvious reasons.

I saw your later response to Seebs, but just to mention -- if
strncpy is the answer, you're very likely asking the wrong question.
If the data being copied just fits the target, the target won't be
properly null-terminated. If the target is bigger than the source,
the target will be passed with multiple null characters, which are
most likely useless.

If you really want a data structure consisting of a sequence of
non-null characters followed by *zero* or more null characters,
filling the entire array, then strncpy is the right tool. But more
often, what you really want is a string, which is a sequence of
non-null characters terminated by a single null character; what
follows the null terminator typically doesn't matter, and there's
no point in wasting effort initializing it.

(And of course don't confuse the null character, '\0', with a null
pointer, NULL.)
 
M

Mark

Keith Thompson said:
I saw your later response to Seebs, but just to mention -- if
strncpy is the answer, you're very likely asking the wrong question.
If the data being copied just fits the target, the target won't be
properly null-terminated. If the target is bigger than the source,
the target will be passed with multiple null characters, which are
most likely useless.

If you really want a data structure consisting of a sequence of
non-null characters followed by *zero* or more null characters,
filling the entire array, then strncpy is the right tool. But more
often, what you really want is a string, which is a sequence of
non-null characters terminated by a single null character; what
follows the null terminator typically doesn't matter, and there's
no point in wasting effort initializing it.

(And of course don't confuse the null character, '\0', with a null
pointer, NULL.)

All fair points, and I do know all that. I was quite literally being
stupid - just a brainfart.
 
D

dgoodmaniii

Eric Sosman said:
That would work: "Look before you leap." An alternative
would be to use the argc value, which tells you the total
number of command-line arguments.

The reason I was having trouble there was that I was
dereferencing the pointer. The *value* of the pointer
shouldn't be NULL; rather, the *address* should be NULL, to
invoke that part of the program. It now reads:
if (argv == NULL) {
And all is well.
Take your own route, do what works for you. In close to
forty years of writing programs in dozens of languages, it's
always -- always! -- seemed to me that handling the exceptional
cases is best thought about first, not last. One big reason
is that it's not enough just to detect a strangeness: You must
also choose how to respond to it. That choice may have profound
effects on the overall program structure and on the definitions
of your functions/subroutines/lambdas/methods, and is the sort
of thing that's hard to "stick on" at the end.

Well, I certainly don't want to disregard the wisdom of my
elders. (Whether or not any of you are older than I am.)
In this case, I didn't think these were really "exceptional
cases," as you put it; they were just cases that wouldn't
work. As such, I thought I'd write the code for the cases
that can work, and write later code to reject data that
can't possibly work---like triple-digit exponents for
doubles.
Ah, but is there enough room in the string? Those command-
line arguments, for example: If one of them is "12;3e7" you can
only be sure of seven characters (including the '\0'). If you
try to store the eleven characters of "123000000;" into the
space that suffices for seven, ...

Ah! Yes; I was still thinking in the mode of the other
direction, where I allocated a string that was safely large
enough. In that program, I could just move the null
character back, provided that I didn't move it back past the
allocated space. In this case, the string is set
automatically when received into argv, and I don't have that
option. Hmm. I really have little idea how to handle this.

Do I need to measure how much bigger this string must be,
then call realloc() to make sure I've got room?
Okay. A full-scale job that squeezes the last little bit of
accuracy out of the conversion is, to coin a phrase, "non-trivial."

Yes, and probably (by which I mean "certainly") beyond my
competence. But I want to do what little I can do right, if
I can.
 
S

Seebs

The reason I was having trouble there was that I was
dereferencing the pointer. The *value* of the pointer
shouldn't be NULL; rather, the *address* should be NULL, to
invoke that part of the program. It now reads:
if (argv == NULL) {
And all is well.

That seems very unlikely.

argv should never be null. argv is always a valid pointer to an array of
other pointers, the last one of which is null.

-s
 
D

dgoodmaniii

Ben Bacarisse said:
Most people are quite friendly here, so don't be afraid to post again
if you want the code to be looked over once you have done what you
feel you can.

Absolutely. Usenet is the best place to find help. I've
learned almost everything I know about computers in general,
Unix, Linux, TeX, Metafont, and so on (more than my C
knowledge would indicate, I promise) from Usenet. If you're
an arrogant jerk demanding free tech support, you won't find
it welcoming. But if you do your homework and don't expect
everyone to do everything for you, it'll be a great help.

I was pleased to find comp.lang.c as helpful as the other
groups I've used. Thank you all again.
 
D

dgoodmaniii

Seebs said:
argv should never be null. argv is always a valid pointer to an array of
other pointers, the last one of which is null.

You're right.

But testing whether (*(++argv)) is null *does* work, and
sending *(argv-1) to my function works. It seems like this
doesn't really step out of array bounds, then. When I test
*(++argv), when a non-'-' command line argument is passed,
I'm testing *argv[argc], which is null. So that's fine.

When there is no such argument, though, I *am* stepping
beyond the array. I think I may finally understand this.
Why not test whether *argv is null? What do you all think
of this?
*******
while (*(++argv) != NULL && *argv[0] == '-') {
if (isdigit((*argv+1)[1]) || (*argv+1)[1] == '.')
break; /* negative numbers are not optional args */
while (c = *++argv[0])
switch (c) {
default:
fprintf(stderr,"dec: illegal option \"%c\"\n",c);
break;
}
}
if (*argv != NULL) {
printf("%f\n",doztodec(*(argv)));
return 0;
}
while (getword(doznum,MAXLINE) != EOF) {
printf("%f\n",doztodec(doznum));
}
return 0;
*******
This seems to do everything I want it to do. (That is, to
convert the command line argument if present, to convert
what it receives on stdin if not.) Am I still missing any
hidden errors here?
 
N

Nick Keighley

why? and why the smiley? You do realise that any problem with strcpy()
(non-string in source, not enough space in target) apply EQUALLY to
strlen/memcpy? Plus strcpy/memcpy is more expensive- it scans the
string twice.


and a couple of possible problems that may be introduced by strncpy()

I normally go with strncpy -

why? Have you read its specification?

I chose went with memcpy for no particular
reason.  It's strcpy I have problems with - for obvious reasons.

which are?
 
M

Mark

Nick Keighley said:
why? and why the smiley? You do realise that any problem with strcpy()
(non-string in source, not enough space in target) apply EQUALLY to
strlen/memcpy? Plus strcpy/memcpy is more expensive- it scans the
string twice.

I'll refer you to my earlier answers: I was being stupid and not
thinking properly at the end of a long day - simple as that.

Okay.

To give a longer answer, I don't use strcpy much...but in my own code,
for various reasons I have the length precalculated in any case, so the
cost of strncpy/memcpy is no big deal. I completely acknowledge that
(in this case) strcpy is the better choice by far. A little less haste
would have changed that, as would a second more of considering the
follow-up.

Okay?

Can I put a smiley now? :p
(In case it comes across wrongly, I am just lightening the mood)
 
B

Ben Bacarisse

Seebs said:
argv should never be null. argv is always a valid pointer to an array of
other pointers, the last one of which is null.

You're right.

But testing whether (*(++argv)) is null *does* work, and
sending *(argv-1) to my function works. It seems like this
doesn't really step out of array bounds, then. When I test
*(++argv), when a non-'-' command line argument is passed,
I'm testing *argv[argc], which is null. So that's fine.

argc can be 0 with *argv == NULL on some systems. When that happens,
argv may be a pointer to (the start of) a single-element array in
which case *++argv does step outside the array.
When there is no such argument, though, I *am* stepping
beyond the array. I think I may finally understand this.
Why not test whether *argv is null?

Yes, you need to test *argv for NULL or, alternatively, for argc being
0. This makes me wonder why you don't!
What do you all think of this?
*******
while (*(++argv) != NULL && *argv[0] == '-') {

You have to test *argv not *++argv. This alters almost everything
that follows, though you'll get away with it if there is always a
non-NULL argv[0].
if (isdigit((*argv+1)[1]) || (*argv+1)[1] == '.')

I don't think you meant that. argv[0][1] is the character that
follows the '-' you have just identified in the 'while' test. If you
want to write that with fewer indexes, that would be *(argv[0] + 1) or
*(*argv + 1) or (*argv + 1)[0] but argv[0][1] is so much clearer than
any of the alternatives. (*argv + 1)[1] is the second digit. Did you
test with single digit negative number?
break; /* negative numbers are not optional args */
while (c = *++argv[0])

Whilst I don't object to modifying argv, modifying argv[0] worries me
a little. It's permitted, but it complicates matters (debugging in
particular) so I prefer to set a 'flags' pointer to the current arg
and "walk" that.
switch (c) {
default:
fprintf(stderr,"dec: illegal option \"%c\"\n",c);
break;
}
}
if (*argv != NULL) {
printf("%f\n",doztodec(*(argv)));
return 0;
}
while (getword(doznum,MAXLINE) != EOF) {
printf("%f\n",doztodec(doznum));
}
return 0;

<snip>
 
M

Mark

Richard Heathfield said:
Mark wrote:

[re strcpy/strncpy]
Can I put a smiley now? :p
(In case it comes across wrongly, I am just lightening the mood)

It is actually quite difficult to express disagreement on Usenet (and,
it sometimes seems, in real life) without connotations of antagonism and
irritation - even when one's comments are not intended to express these
ideas, they are sometimes read that way anyway. I think you may have
over-interpreted Nick K's and my responses.

Actually, I was actually trying to ensure it was clear that *I* wasn't
irritated. I didn't take any of the comments badly - it was me that was
being stupid. My only irritation was with myself. ;-)
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top