dh, the daemon helper - Unix
This is a discussion on dh, the daemon helper - Unix ; Rainer Weikusat writes:
> Indeed. a[n] is defined as being identical to *(a + n), hence &a[n] is
> the same as &*(a + n). Put into words: A 'pointer-to-type' value is
> derefenced to yield a value of type ...
-
Re: dh, the daemon helper
Rainer Weikusat writes:
> Indeed. a[n] is defined as being identical to *(a + n), hence &a[n] is
> the same as &*(a + n). Put into words: A 'pointer-to-type' value is
> derefenced to yield a value of type 'type', the address of which is
> then taken, resulting in a value of type 'pointer-to-type': & and *
> are inverse operations in this respect.
But there is a technicality about &*. & and * cancel out in the sense
that the standard says that neither is evaluated[1] so any description
that suggests &* is a de-reference followed by taking the address of
the result could lead people astray.
In particular, given T x[N]; the expression &x[N] (== &*(x + N) ==
x + N) is legal even though *(x + N) is undefined behaviour.
[1] There are some extra words: the constraints still apply and the
result is not a lvalue but the key part is that applying & to a *
expression is defined by removing both operators, not by evaluating
them.
--
Ben.
-
Re: dh, the daemon helper
Ben Bacarisse writes:
> Rainer Weikusat writes:
>> Indeed. a[n] is defined as being identical to *(a + n), hence &a[n] is
>> the same as &*(a + n). Put into words: A 'pointer-to-type' value is
>> derefenced to yield a value of type 'type', the address of which is
>> then taken, resulting in a value of type 'pointer-to-type': & and *
>> are inverse operations in this respect.
>
> But there is a technicality about &*. & and * cancel out in the sense
> that the standard says that neither is evaluated[1] so any description
> that suggests &* is a de-reference followed by taking the address of
> the result could lead people astray.
Well, but &* is a de-reference, followed by taking the address of the
result. Which cancels out, so the sequence is a nop. I explicitly
intended to imply that any such sequence is killed by the compiler
because it doesn't mean anything.
> In particular, given T x[N]; the expression &x[N] (== &*(x + N) ==
> x + N) is legal even though *(x + N) is undefined behaviour.
>
> [1] There are some extra words: the constraints still apply and the
> result is not a lvalue but the key part is that applying & to a *
> expression is defined by removing both operators, not by evaluating
> them.
In turn, applying & to any valid operand means the operand isn't
evaluated, but its address is used instead. Consequently, since
x + N is required to be a valid pointer, &*(x + N) must be valid
pointer, too. Otherwise, the &* would not be a two letter sequence
whose combined meaning is 'no effect'.
Or I completely misunderstand you.
?
-
Re: dh, the daemon helper
Rainer Weikusat writes:
> scott@slp53.sl.home (Scott Lurndal) writes:
>> Rainer Weikusat writes:
>>> ... last but not
>>>least - SIGSEGV is sent by the kernel to a process which attempted an
>>>invalid memory access. The default action usually involves to
>>>terminate the process and create a core dump of it[*].
>> [snip]
>>
>>> [*] This very handy feature is typically disabled by 'current'
>>> Linux-distribution, either to conceal the bugginess of the
>>> software or because nobody wants to (or knows how to) fix it,
>>> anyway.
>>
>> This is done for a very simple reason. A significant majority of
>> the users of such distributions don't really care for core dumps
>> filling their filesystem (and a poorly written daemon could quickly
>> fill a filesystem with fairly useless core files).
>
> The problem with this approach is that it is not possible to decide
> beforehand when core dumps should rather have been enabled. Generally
> disabling them basically means to voluntarily decide to have no
> interest in ever fixing a problem which would otherwise have caused
> one, including to never help with fixing such a problem.
>
> This is a 'classic' example of how to remain comfortable in face of
> (suspected) bad news by proactively shooting the mailman, based on the
> assumption that these 'bad news' will never have any practical
> relevance.
That's a bit extreme, isn't it? A core dump is in general neither
necessary nor sufficient to help fix problems.
I myself try to fix bugs that I encounter, but I find that the core file
generated by a random program crashing unexpectedly is not very useful.
Generally the program in question has been stripped of debug info, so I
have to recompile it using -g, at which point it no longer matches the
core file. So in any case I have to be able to reproduce the bug before
I can start trying to fix it. And at that point a core file is not
really necessary; running the program under a debugger and waiting for
it to crash is better than using a core dump, because I also get
information about open files, etc.
If the bug is hard to reproduce, the core file is of limited utility
even when it does go with an unstripped binary. It contains the state
of the program itself, but it doesn't contain the state of the rest of
the system (what do files contain, what other processes are interacting
with this one), nor the history of the program (what was the input data,
what branches were taken, etc). These things are, in my experience,
very often critical in finding a bug, especially an irreproducible one.
I do keep core dumps enabled on my systems, but mostly out of
convenience. On most of those few occasions when I really want a core
dump, I know in advance (e.g. I'm about to run a program that I am
pretty sure is going to crash), so I could just turn it on at that time,
but I just leave it on all the time out of laziness. The other reason
is that the core file serves as a visible reminder that something
crashed, and that I should investigate it when I have time, but for this
purpose the contents of the dump are really irrelevant. (An entry in a
log file would be just as good, though less conspicuous.) So the vast
majority of core files generated on my systems are deleted without ever
being examined, and this is entirely consistent with getting things
fixed.
If you further discount these advantages for users who do not themselves
have the knowledge to fix bugs (who are certainly the majority), then
IMHO it is entirely reasonable for a distribution to disable core dumps
by default. It isn't my personal preference, as I said above, but
that's why they're easy to enable again.
-
Re: dh, the daemon helper
Rainer Weikusat wrote:
> [... default suppression of core dumps ...]
> The problem with this approach is that it is not possible to decide
> beforehand when core dumps should rather have been enabled. Generally
> disabling them basically means to voluntarily decide to have no
> interest in ever fixing a problem which would otherwise have caused
> one, including to never help with fixing such a problem.
>
> This is a 'classic' example of how to remain comfortable in face of
> (suspected) bad news by proactively shooting the mailman, based on the
> assumption that these 'bad news' will never have any practical
> relevance.
Consider also the security and privacy implications. A
dump of a crashed program that was manipulating sensitive data
is likely to reveal the data -- quite possibly in unencrypted
form -- to anyone who gets a look at the core file. Note that
the sensitivity of the data is a matter for the application's
user, not its developer, to decide. An "opt-in" rather than an
"opt-out" policy seems respectful of that distinction.
--
Eric Sosman
esosman@ieee-dot-org.invalid
-
Re: dh, the daemon helper
Rainer Weikusat writes:
> Ben Bacarisse writes:
>> Rainer Weikusat writes:
>>> Indeed. a[n] is defined as being identical to *(a + n), hence &a[n] is
>>> the same as &*(a + n). Put into words: A 'pointer-to-type' value is
>>> derefenced to yield a value of type 'type', the address of which is
>>> then taken, resulting in a value of type 'pointer-to-type': & and *
>>> are inverse operations in this respect.
>>
>> But there is a technicality about &*. & and * cancel out in the sense
>> that the standard says that neither is evaluated[1] so any description
>> that suggests &* is a de-reference followed by taking the address of
>> the result could lead people astray.
>
> Well, but &* is a de-reference, followed by taking the address of the
> result. Which cancels out, so the sequence is a nop. I explicitly
> intended to imply that any such sequence is killed by the compiler
> because it doesn't mean anything.
I can't make those words mean the same as mine, so I think we disagree
but I am not sure on what. The bit that bothers me is the notion that
an & can cancel out the effect of an operation that might be undefined.
&* /looks/ like a de-reference and an address-of operation but it is
not. There must be no de-reference in a conforming implementation.
Also, it is not exactly a no-op since &*x is not the same as x, even
when x is a valid pointer (though they have the same value).
>> In particular, given T x[N]; the expression &x[N] (== &*(x + N) ==
>> x + N) is legal even though *(x + N) is undefined behaviour.
>>
>> [1] There are some extra words: the constraints still apply and the
>> result is not a lvalue but the key part is that applying & to a *
>> expression is defined by removing both operators, not by evaluating
>> them.
>
> In turn, applying & to any valid operand means the operand isn't
> evaluated, but its address is used instead.
You must be using "evaluated" or "operand" in some different way to
me. In an expression like &f()->x the operand of & is evaluated. I
call f()->x the operand of & in the above. It is evaluated to yield
an lvalue whose address is the result of the whole expression.
(Note that -> is not defined in terms of . and * so there is no
implied &* in the above expression; but if you don't like that
example, then compound literals provide another: &(int){f()} clearly
requires that the operand of & be evaluated.)
> Consequently, since
> x + N is required to be a valid pointer, &*(x + N) must be valid
> pointer, too. Otherwise, the &* would not be a two letter sequence
> whose combined meaning is 'no effect'.
>
> Or I completely misunderstand you.
I don't know. I don't like calling &* a no-op (since it has a small
effect on the meaning of the expression it is applied to) but I also
think that explaining it in terms of a de-reference sounds confusing
since no de-reference happens.
--
Ben.
-
Re: dh, the daemon helper
Eric Sosman writes:
> Rainer Weikusat wrote:
>> [... default suppression of core dumps ...]
>> The problem with this approach is that it is not possible to decide
>> beforehand when core dumps should rather have been enabled. Generally
>> disabling them basically means to voluntarily decide to have no
>> interest in ever fixing a problem which would otherwise have caused
>> one, including to never help with fixing such a problem.
>>
>> This is a 'classic' example of how to remain comfortable in face of
>> (suspected) bad news by proactively shooting the mailman, based on the
>> assumption that these 'bad news' will never have any practical
>> relevance.
>
> Consider also the security and privacy implications. A
> dump of a crashed program that was manipulating sensitive data
> is likely to reveal the data -- quite possibly in unencrypted
> form -- to anyone who gets a look at the core file. Note that
> the sensitivity of the data is a matter for the application's
> user, not its developer, to decide. An "opt-in" rather than an
> "opt-out" policy seems respectful of that distinction.
Interestingly, on my system (FreeBSD) even pages that were mlock()ed are
included in a core file. Arguably that's wrong. But I suppose this
means if you have sensitive data that must not hit the disk, you should
use not only mlock() but also setrlimit(RLIMIT_CORE, {0, max}).
-
Re: dh, the daemon helper
On Nov 2, 12:09 pm, Rainer Weikusat wrote:
>
> Well, but &* is a de-reference, followed by taking the address of the
> result. Which cancels out, so the sequence is a nop. I explicitly
> intended to imply that any such sequence is killed by the compiler
> because it doesn't mean anything.
I added some decoration to the code to quiet splint as much as
possible. But it's been a while ago, I don't remember all of them ...
-
Re: dh, the daemon helper
On Oct 31, 4:31 pm, vipps...@gmail.com wrote:
>
> >ftp://ftp.isp2dial.com/users/jak/src/dh/
>
> First of all, you use perror/exit a lot. I'd write a function/macro if
> I were you.
Replacing two inline statements with one function call has dubious
value. I tend to use functions when the body is more significant, as
in logtime().
> line 43,44 it wouldn't be bad if you had a comment explaining those
> magic numbers.
The macro names INTERVAL_ seemed self evident to me. Notice it's used
with a nanosleep. But why? Good question.
In an earlier revision of the code, I needed a sleep to make sure the
parent process had time to die, and the child was adopted by init,
*before* execing the target deamon. Very important.
However, in a later revision, I added pipes to synchronize the
grandparent and the child, so now the sleep should never happen. But
it's still there, just in case. Now, it primarily serves to alert the
programmer that something is not working as expected.
> line 52 I think most C programmers prefer const char [] over char
> const [] (no actual difference)
I see that's been discussed later in the thread. As for style, I
listen to get ideas from other people, but conformity to poplular
culture holds little appeal for me. I'm too independent for that.
> line 66,74 that should be isspace((unsigned char)**ts). is* and to*
> functions expect a positive integer or EOF, and char may be signed.
I thought EOF was -1. What's the problem?
> line 62-81 can be replaced with keep = strtok(*ts, " \n\t\v\f\r");
> if(keep) *ts = keep; strtok(NULL, " \n\t\v\f\r"); with only difference
> that it won't behave exactly the same if the implementation has more
> than the minimum characters in the space character class. (see IEEE
> 1003.1, 2004: 7.3.1 LC_CTYPE). Since I don't like either solution I
> might've considered to write a map function, and use isspace.
I don't have time to analyze that now, so no comment.
> line 143,156 can be replaced with if(lockname[0] == 0). There's no
> reason to process the whole string. also line 369
Good catch. I'll fix that up.
> line 155 IMHO the parentheses in the expression &(argv[optind])
> should be removed, like: trim(&argv[optind])
That may have been a decoration for the sake of keeping splint quiet.
But I don't really remember now ...
> I'm curious how your code works since in line 161 you exit if usage is
> non-zero, and at that point it can't have the value 0.
> I haven't compiled it so I might be missing something.
Works for me. Please compile and try it out. I provided a makefile.
> line 177-213 should be replaced with some loop.
> line 214 the cast is not needed. It'd be better if you just had
> open_max a long instead of an int though.
> line 225-226 change the conversion specifier from u to d and remove
> the (unsigned int) cast. There's no benifit.
> line 353 you have several memory leaks after this line, since you
> do not free the return value of strdup on error.
> line 395,395 can be replaced with a simple free(exectemp); free(NULL)
> is defined to do nothing.
> line 473,478 getpid returns a pid_t, which might not be int (it's
> allowed to be any signed integer type). Use printf("%ld",
> (long)getpid());
> (you won't find any systems that have pid_t's with values bigger than
> 2^31-1 but LONG_MAX at 2^31-1 - and even then, your process must have
> such process id, which would give you implementation-defined behavior
> or an implementation-defined signal)
So many details. I'll try to study them when I have more time.
> Lastly, I think you're overly verbose with error messages and error
> checking.
Failure to check and report every possible error is a great
programming sin! Most of those errors will never happen under normal
conditions. But if they do, the error messages are a hint something's
gone wrong with the system itself.
ftp://ftp.isp2dial.com/users/jak/src/dh/
--
Webmail for Dialup Users
http://www.isp2dial.com/freeaccounts.html
-
Re: dh, the daemon helper
On Nov 3, 1:23 am, John Kelly wrote:
> On Oct 31, 4:31 pm, vipps...@gmail.com wrote:
>
> > >ftp://ftp.isp2dial.com/users/jak/src/dh/
>
> > First of all, you use perror/exit a lot. I'd write a function/macro if
> > I were you.
>
> Replacing two inline statements with one function call has dubious
> value. I tend to use functions when the body is more significant, as
> in logtime().
Yeah, you don't win much - it's just what I'd do.
> > line 43,44 it wouldn't be bad if you had a comment explaining those
> > magic numbers.
>
> The macro names INTERVAL_ seemed self evident to me. Notice it's used
> with a nanosleep. But why? Good question.
Of course they are self evident to you, you wrote all that. ;-)
> > line 66,74 that should be isspace((unsigned char)**ts). is* and to*
> > functions expect a positive integer or EOF, and char may be signed.
>
> I thought EOF was -1. What's the problem?
Actually the value of EOF is not related. Even if it was, EOF is
guaranteed to be a negative integer, in the range [INT_MIN, -1]. (ie
it doesn't need to be -1)
Whta the problem is, is that the values that can be passed to is* and
to* functions without breaking them are:
o EOF
o [0, UCHAR_MAX]
The value of a char may not be in that range (ie you might pass -3,
with EOF being -1)
What can happend, many things. Depends on your implemenation, but you
should know this is just incorrect to do. (invokes undefined behavior
under both POSIX and ISO C)
> > line 62-81 can be replaced with keep = strtok(*ts, " \n\t\v\f\r");
> > if(keep) *ts = keep; strtok(NULL, " \n\t\v\f\r"); with only difference
> > that it won't behave exactly the same if the implementation has more
> > than the minimum characters in the space character class. (see IEEE
> > 1003.1, 2004: 7.3.1 LC_CTYPE). Since I don't like either solution I
> > might've considered to write a map function, and use isspace.
>
> I don't have time to analyze that now, so no comment.
Well, on another look, the last strtok call is not needed.
It's equivalent to if((keep = strtok(*ts, " \r\n\v\f\t")) != NULL) *ts
= keep;
(minus the minute details)
> > I'm curious how your code works since in line 161 you exit if usage is
> > non-zero, and at that point it can't have the value 0.
> > I haven't compiled it so I might be missing something.
>
> Works for me. Please compile and try it out. I provided a makefile.
Will do.
> > Lastly, I think you're overly verbose with error messages and error
> > checking.
>
> Failure to check and report every possible error is a great
> programming sin! Most of those errors will never happen under normal
> conditions. But if they do, the error messages are a hint something's
> gone wrong with the system itself.
I agree, but I think some of your error checks are imaginary. I'm not
sure thought, I haven't really thought of every situation with your
code.
-
Re: dh, the daemon helper
On Nov 2, 7:10 pm, vipps...@gmail.com wrote:
> > > line 66,74 that should be isspace((unsigned char)**ts). is* and to*
> > > functions expect a positive integer or EOF, and char may be signed.
>
> > I thought EOF was -1. What's the problem?
>
> Actually the value of EOF is not related. Even if it was, EOF is
> guaranteed to be a negative integer, in the range [INT_MIN, -1]. (ie
> it doesn't need to be -1)
> Whta the problem is, is that the values that can be passed to is* and
> to* functions without breaking them are:
>
> o EOF
> o [0, UCHAR_MAX]
>
> The value of a char may not be in that range (ie you might pass -3,
> with EOF being -1)
>
> What can happend, many things. Depends on your implemenation, but you
> should know this is just incorrect to do. (invokes undefined behavior
> under both POSIX and ISO C)
I see.
Earlier in the thread, Rainer said with C it doesn't matter where a
char comes from, though I don't understand what he meant.
Nevertheless, if the value violates the isspace() constraint, the
result is unpredictable. But how is that a defect? Unless my raw
(int) call to isspace() can crash the OS, or produce confusing output,
I don't see how casting the value offers any benefit beyond the
imaginary.
--
Webmail for Dialup Users
http://www.isp2dial.com/freeaccounts.html
-
Re: dh, the daemon helper
Eric Sosman writes:
> Rainer Weikusat wrote:
>> [... default suppression of core dumps ...]
>> The problem with this approach is that it is not possible to decide
>> beforehand when core dumps should rather have been enabled.
[...]
> Consider also the security and privacy implications. A
> dump of a crashed program that was manipulating sensitive data
> is likely to reveal the data -- quite possibly in unencrypted
> form -- to anyone who gets a look at the core file.
Keeping anything 'sensitive' on a time-shared system where
untrustworthy people have 'superuser access' ('sufficient privileges
to read arbitrary files belonging to other users') is basically a
mistake (it is even a mistake when combined with MAC, because the
software intended to enforce that could have errors).
-
Re: dh, the daemon helper
Peter Nilsson wrote:
> vipps...@gmail.com wrote:
>> CBFalconer wrote:
>>> You didn't cross-post and set follow-ups. So the
>>> originator of the query will never see your answer,
>>> unless you also committed the sin of multi-posting.
>> You're possibly right. I don't know how to do that
>> with googles interface.
>
> Same way you would with any other newsreader: enter
> comma separated list of newsgroups, and add a followup.
I use Thunderbird as my main newsreader. I'm not sure whether a comma
delimited list is permitted. I'm using this message as a test by using a
adding ", comp.unix.programmer" to the Newsgroup box at the top of the
form. However, even if that works, the usual way I do it in Thunderbird
is to click on a new header line, select "Newsgroup:" as the header
type, and type in the second group name in the header value field.
That's quite different from the way it's done in Google Groups.
Saying "add a followup" doesn't really address the issue at all - the
issue is how to actually do that. In Google Groups, you have to select a
link titled "Add a followup-to", which adds a new box to the form where
you can fill in multiple group names, separated by commas. In
Thunderbird, for each group you want to add, you click on a new header
line, select "Followup-To:" as the header type, and then type in the
group name.
-
Re: dh, the daemon helper
On Nov 3, 6:13 am, John Kelly wrote:
> On Nov 2, 7:10 pm, vipps...@gmail.com wrote:
>
> > > > line 66,74 that should be isspace((unsigned char)**ts). is* and to*
> > > > functions expect a positive integer or EOF, and char may be signed.
>
> > > I thought EOF was -1. What's the problem?
>
> > Actually the value of EOF is not related. Even if it was, EOF is
> > guaranteed to be a negative integer, in the range [INT_MIN, -1]. (ie
> > it doesn't need to be -1)
> > Whta the problem is, is that the values that can be passed to is* and
> > to* functions without breaking them are:
>
> > o EOF
> > o [0, UCHAR_MAX]
>
> > The value of a char may not be in that range (ie you might pass -3,
> > with EOF being -1)
>
> > What can happend, many things. Depends on your implemenation, but you
> > should know this is just incorrect to do. (invokes undefined behavior
> > under both POSIX and ISO C)
>
> I see.
>
> Earlier in the thread, Rainer said with C it doesn't matter where a
> char comes from, though I don't understand what he meant.
Well Rainer said a lot of things that I didn't understand, and it's
not because I lack any necessary knowledge.
> Nevertheless, if the value violates the isspace() constraint, the
> result is unpredictable. But how is that a defect? Unless my raw
> (int) call to isspace() can crash the OS, or produce confusing output,
> I don't see how casting the value offers any benefit beyond the
> imaginary.
It's a defect simply because the behavior is undefined.
Now what could happend? The OS crashing is one thing (if the value at
__istable[c] is a trap representation)
Producing confusing output is more likely, since you don't know what
resides in __istable[c] (note that __istable is the table your
implementation uses to map characters - that doesn't mean you *do*
have one)
You don't have to worry about what will happend if you're a programmer
- just avoid UB. If you want to take advantage of it, you can look
into your implementation and see what is possible and what not for
*your* implementation.
-
Re: dh, the daemon helper
On Nov 3, 2:10 am, vipps...@gmail.com wrote:
> On Nov 3, 1:23 am, John Kelly wrote:
>
> > On Oct 31, 4:31 pm, vipps...@gmail.com wrote:
> >
> > > line 66,74 that should be isspace((unsigned char)**ts). is* and to*
> > > functions expect a positive integer or EOF, and char may be signed.
>
> > I thought EOF was -1. What's the problem?
>
> Actually the value of EOF is not related. Even if it was, EOF is
> guaranteed to be a negative integer, in the range [INT_MIN, -1]. (ie
> it doesn't need to be -1)
> Whta the problem is, is that the values that can be passed to is* and
> to* functions without breaking them are:
>
> o EOF
> o [0, UCHAR_MAX]
>
> The value of a char may not be in that range (ie you might pass -3,
> with EOF being -1)
>
> What can happend, many things. Depends on your implemenation, but you
> should know this is just incorrect to do. (invokes undefined behavior
> under both POSIX and ISO C)
What I wanted to add is that, technically, (unsigned char)**ts is also
undefined behavior;
**ts is allowed to be a trap representation.
It'd be more correct as *(unsigned char *)*ts.
-
Re: dh, the daemon helper
Nate Eldredge writes:
> Rainer Weikusat writes:
>> scott@slp53.sl.home (Scott Lurndal) writes:
[supressing coredumps by default]
>>> This is done for a very simple reason. A significant majority of
>>> the users of such distributions don't really care for core dumps
>>> filling their filesystem (and a poorly written daemon could quickly
>>> fill a filesystem with fairly useless core files).
>>
>> The problem with this approach is that it is not possible to decide
>> beforehand when core dumps should rather have been enabled. Generally
>> disabling them basically means to voluntarily decide to have no
>> interest in ever fixing a problem which would otherwise have caused
>> one, including to never help with fixing such a problem.
[...]
> That's a bit extreme, isn't it? A core dump is in general neither
> necessary nor sufficient to help fix problems.
And a compiler is in general neither necessary nor sufficient to
program computers --- using the front-panel switches to enter octal
numbers would be possible, too. The point was supposed to be that a
coredump is the only source of accurate information about an
unexpected 'crash' of some program which happened in the past.
> I myself try to fix bugs that I encounter, but I find that the core file
> generated by a random program crashing unexpectedly is not very useful.
> Generally the program in question has been stripped of debug info, so I
> have to recompile it using -g, at which point it no longer matches the
> core file.
That's a different problem: Debugging tools don't work very well with
binaries compiled without debugging information. But you could still
(at least) determine where the program met its untimely death and what
the contents of the CPU registers where at that time. Digging through
the contents of the stack do determine the call chain would still be
possible, too. But generally, I agree with you: Binaries compiled
without debugging information are too hard to debug to make this worth
the effort except in special cases. Which would be a good reason to
not do this.
> So in any case I have to be able to reproduce the bug before
> I can start trying to fix it.
Generally, this is wrong. It is necessary to be able to reproduce the
bug in order to experimentally verify that a supposed fix for it
actually works.
> And at that point a core file is not really necessary; running the
> program under a debugger and waiting for it to crash is better than
> using a core dump, because I also get information about open files,
> etc.
Well, the program could be using 39 different threads and be running
on a small multiprocessor, continously interacting with 170 - 200
'client programs' running on appliances distributed all around the
world, IOW, the only actual information about the problem could be an
occasional coredump. This is a real-world example and I have found
this particular error a while ago (after two years of slowly hunting
it down).
> If the bug is hard to reproduce, the core file is of limited utility
> even when it does go with an unstripped binary. It contains the state
> of the program itself, but it doesn't contain the state of the rest of
> the system (what do files contain, what other processes are interacting
> with this one), nor the history of the program (what was the input data,
> what branches were taken, etc). These things are, in my experience,
> very often critical in finding a bug, especially an irreproducible
> one.
Incomplete information is a lot more helpful than 'no
information'. Additionally, (in my experience) most 'crashes' are
caused by simple errors (like not checking for null pointers before
derefencing a pointer value) on rarely taken codepaths. And these are
often extermly simple to fix, provided it is known where the program
crashed because of which operation.
> I do keep core dumps enabled on my systems, but mostly out of
> convenience. On most of those few occasions when I really want a core
> dump, I know in advance
[...]
> The other reason is that the core file serves as a visible reminder
> that something crashed, and that I should investigate it when I have
> time, but for this purpose the contents of the dump are really
> irrelevant. (An entry in a log file would be just as good, though
> less conspicuous.)
[...]
> If you further discount these advantages for users who do not themselves
> have the knowledge to fix bugs (who are certainly the majority), then
> IMHO it is entirely reasonable for a distribution to disable core dumps
> by default.
Especially for users who do not themselves have this knowledge, having
a core dump would be an advantage, provided the user was interested in
getting the issue resolved. "It crashed yesterday, but I do not know
when, why or where and not even which signal ocurred" is completely
useless as a bug report: It communicates the fact that some user is
convinced there would be at least one unknown bug, which lead to the
program exiting 'somehow' 'somewhen'.
There is basically no possible reply to that save 'Sorry, but without
any information, I cannot possibly do anything to help you'.
NB: I do not claim that 'reasons for disabling coredump' would
generally be invalid, just trying to demonstrate that this involved a
tradeoff which can backfire.
-
Re: dh, the daemon helper
vippstar@gmail.com wrote:
> On Nov 3, 2:10 am, vipps...@gmail.com wrote:
>> On Nov 3, 1:23 am, John Kelly wrote:
>>
>>> On Oct 31, 4:31 pm, vipps...@gmail.com wrote:
>>>
>>>> line 66,74 that should be isspace((unsigned char)**ts). is* and to*
>>>> functions expect a positive integer or EOF, and char may be signed.
>>> I thought EOF was -1. What's the problem?
>> Actually the value of EOF is not related. Even if it was, EOF is
>> guaranteed to be a negative integer, in the range [INT_MIN, -1]. (ie
>> it doesn't need to be -1)
>> Whta the problem is, is that the values that can be passed to is* and
>> to* functions without breaking them are:
>>
>> o EOF
>> o [0, UCHAR_MAX]
>>
>> The value of a char may not be in that range (ie you might pass -3,
>> with EOF being -1)
>>
>> What can happend, many things. Depends on your implemenation, but you
>> should know this is just incorrect to do. (invokes undefined behavior
>> under both POSIX and ISO C)
>
> What I wanted to add is that, technically, (unsigned char)**ts is also
> undefined behavior;
> **ts is allowed to be a trap representation.
> It'd be more correct as *(unsigned char *)*ts.
If you're trying to classify a character that holds a trap
representation, your program is already in more trouble than a
few casts can cure. That is, the fact that your program is asking
about the space-ness or digit-ness of an uninitialized character
variable is evidence that it's already gone off the rails.
When you get a char from someplace, whether it be via a pointer
or just directly from a char variable, the way to handle it with
the functions is to convert that char value to unsigned
char and thence to int:
if (isupper( (unsigned char) the_char )) ...
This form mimics the C Standard's own description of acceptable
argument values: an int equal to EOF or equal to the character
value converted to unsigned char. The formulation you suggest
is type-punning, made more obvious if we think of an ordinary
char variable:
if (isupper( *((unsigned char*) &the_char) )) ...
Type-punning is a regrettable habit, something we must indulge
in from time to time but should avoid when it's not necessary. In
this case it isn't necessary, so I vote to avoid it. Also, there's
the smug satisfaction of knowing that the form I prefer will still
work if ones' complement or signed magnitude machines ever make a
comeback; that's pretty unlikely, but I've been in this industry
long enough to realize that fashions come and go and return ...
--
Eric.Sosman@sun.com
-
Re: dh, the daemon helper
Eric Sosman writes:
[...]
> Also, there's the smug satisfaction of knowing that the form I
> prefer will still work if ones' complement or signed magnitude
> machines ever make a comeback; that's pretty unlikely, but I've been
> in this industry long enough to realize that fashions come and go
> and return ...
The C-standard requires twos' complement for any implementation which
supports integer with any or all of the widths 8, 16, 32 and 64 (via
7.18.1.1, 1 & 3).
-
Re: dh, the daemon helper
On Nov 3, 5:39 pm, Eric Sosman wrote:
> vipps...@gmail.com wrote:
> > What I wanted to add is that, technically, (unsigned char)**ts is also
> > undefined behavior;
> > **ts is allowed to be a trap representation.
> > It'd be more correct as *(unsigned char *)*ts.
>
> If you're trying to classify a character that holds a trap
> representation, your program is already in more trouble than a
> few casts can cure. That is, the fact that your program is asking
> about the space-ness or digit-ness of an uninitialized character
> variable is evidence that it's already gone off the rails.
You're mistaken, **ts is initialized, from user input.
I snip the rest since I generally agree.
-
Re: dh, the daemon helper
On Nov 3, 6:13 am, vipps...@gmail.com wrote:
> > Nevertheless, if the value violates the isspace() constraint, the
> > result is unpredictable. But how is that a defect?
>
> It's a defect simply because the behavior is undefined.
How can you call isspace() with EOF if the value is cast to unsigned?
The "standard" sounds self contradictory.
> The isspace() function shall return non-zero if c is a white-space character;
> otherwise, it shall return 0.
>
> ERRORS
>
> No errors are defined.
So the "standard" says be careful with your input, but if you don't,
we won't say anything. Why follow a self contradictory standard, when
it makes no sense?
--
Webmail for Dialup Users
http://www.isp2dial.com/freeaccounts.html
-
Re: dh, the daemon helper
On Nov 3, 5:52 pm, Rainer Weikusat wrote:
> Eric Sosman writes:
>
> [...]
>
> > Also, there's the smug satisfaction of knowing that the form I
> > prefer will still work if ones' complement or signed magnitude
> > machines ever make a comeback; that's pretty unlikely, but I've been
> > in this industry long enough to realize that fashions come and go
> > and return ...
>
> The C-standard requires twos' complement for any implementation which
> supports integer with any or all of the widths 8, 16, 32 and 64 (via
> 7.18.1.1, 1 & 3).
That's clearly wrong since it contradicts 7.18.1.1, p 3:
> These types are optional. However, if an implementation provides integer types with
> widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a
> two’s complement representation, it shall define the corresponding typedef names.
AFAIK