K
Kleuskes & Moos
A FSM has a hard coded bound on depth.
Since when?
Can you make these parser generators
admit to reaching their limit by asking
them to parse input that goes too deep?
Huh?
A FSM has a hard coded bound on depth.
Can you make these parser generators
admit to reaching their limit by asking
them to parse input that goes too deep?
Kleuskes & Moos said:Where i work, code like that is likely to get you fired on the spot.
Kleuskes & Moos said:Spot on. I hadn't thought of that one.
<reads up on OOM-Killer>
However, if i understand http://linux-mm.org/OOM_Killer correctly
(interesting read, BTW), processes may be killed, but not with a
SIGSEGV, so the program does not crash, but is terminated by the
system. This may not be the desired outcome, but it's not a bug.
And as K. Thompson points out, it may actually kill a different
process, based on the result of badness() and the Law of Least
Surprize.
In any case, malloc should still return NULL if allocation fails, and
the manpage says it does. That processes may be terminated by the
system as a consequence of that call is another matter entirely.
Keith Thompson said:The problem, as I see it, is that by returning a non-null value, the
system promises the program that it can use the allocated memory.
Later invoking the OOM killer when the program actually tries to
use it seems to me to be a violation of that promise.
I understand that overly optimistic allocation can make sense
for stack space; a program will likely never use as much stack
as it could. But I'm not convinced that the same thing applies
to malloc(). If a program calls malloc(), it's telling the OS that
it *will* use that memory (and probably soon). If the system can't
fulfill the request, it should refuse it in the first place.
Do many actual programs malloc() much more memory than they're
actually going to use?
I would hope such library was non-recursive. This has Denial of Service
written all over it, considering that JSON data usually comes from untrusted
sources, and even many scripting languages use the C stack for calls in the
scripting language.
I suppose one could add kludges like a depth counter. I say kludge because
stack memory in C is such an opaque and unmeasureable quantity.
Kleuskes said:But i'd still be interested in your non-portable way, and the above is
insufficient to give me an idea about what you have in mind.
Måns Rullgård said:They do indeed, and that practice is the very reason for overcommit
existing in the first place.
Let me see if i got that straight... You've been arguing that there's
no portable way to cap recursion and a runaway recursive process will
overflow the stack, resulting in a SIGSEGV...
That means the only cap placed on recursion in such a case is the
kernel THROWING a SIGSEGV. This will terminate the process in question
quite effectively, but not to the liking f your client, i imagine.
It's like telling a man "the problem with this car is that you might
run out of gas driving it, if you don't pay attention to the fuel-
gauge". No contradiction, but that doesn't mean nothing is wrong with
it.
Keith Thompson said:Do many actual programs malloc() much more memory than they're
actually going to use?
Dr Nick said:[...]
Where recursion becomes an issue is when you use it for every element of
a sequential data structure. For instance, if a parser's algorithmic
structure were something like:
read_first_token
process_token
recurse(rest of document)
it would probably run into a stack limit on most implementations when
processing any real input.
Most implementations where the compiler doesn't optimise tail recursion
away, anyway.
Eh ... you do understand that 'compiler detects that programmer was a
crackpot and works around that automatically' implies that recursion
is probematic, do you?
Barry Margolin said:Probably not, but that's not relevant. malloc isn't the system call
that adds memory to the process, sbrk is. When malloc find that the
heap is used up, it probably DOES request more memory with sbrk than it
needs just to satisfy the current request.
However, if i understand http://linux-mm.org/OOM_Killer correctly
(interesting read, BTW), processes may be killed, but not with a
SIGSEGV, so the program does not crash, but is terminated by the
system. This may not be the desired outcome, but it's not a bug.
io_x said:for me it is the same recursive function that has to return error; as any other
visible and invisible error; something like
int recursivefunction(int* result, int* value)
{int a, b, c; // esp-=1024 esp<
if(GetCurrentStackPointerValue()<StackLimit-1000)
return -1
....
return recursivefunction(result, value)
}
Nor any portable way to cap non-recursive function calls that overflow
the stack, either.
My complaint has nothing to do with recursion; which
is really the point of my objection to your objections to recursion -
the problem you're trying to avoid cannot be absolutely avoided in any
context; and it can be avoided (with less than absolute success) for
recursive programs just as it can be with non-recursive ones.
Not necessarily; that's just what happens on systems which have SIGSEGV,
or some equivalent mechanism.
I'm commenting on two entirely distinct issues.
1. The lack of any portable way for a C code to avoid making a function
call that requires more stack space than is currently available; there's
not even a portable way to recover from the fact that such a call was
made, which would be a markedly inferior solution to this problem.
Handling a SIGSEGV is indeed an example of such an inferior solution,
but it's not mandated by the C standard.
2. You made a comment about me relying on SIGSEGV; I don't, and I
explained why I can't; but this is only a side issue, not directly
relevant to the first point.
My first point would still apply even if I
had no such restrictions placed on my code, and even if it ran on a
platform which misbehaved in some entirely different way when it ran out
of automatically allocated memory.
It doesn't even matter whether or not
it uses a stack to provide that memory, or some other mechanism, such as
activation records.
Every car I've looked at since my second car search, about 1994, has had
as standard equipment either a buzzer or a flashing light (usually both)
that would provided advance warning if the fuel level was too low. I
would in fact consider any car lacking such warning mechanisms to be
seriously defective.
Where's the buzzer/warning light for approaching the stack limits in C?
The non-portable best that I can do is handling SIGSEGV, which is a
little late; the problem I wanted to avoid has already happened by the
time that signal is raised.
For that matter, I'd settle for the analog of a gas gauge - where can I
find it?
I don't want to make this sound like more of a problem than it really
is; I've been writing programs in C for 30 years now despite the lack of
this feature - it hasn't stopped me, and has only occasionally slowed me
down.
However, but I'm aware of the problems that the lack of such a
feature can cause, and of my helplessness in dealing with those problems.
My point is that recursive code makes only a quantitative difference in
how difficult it is to avoid such problems; it's not a fundamental
qualitative difference.
The improvement in the maintainability of the
code because of the use of a recursive algorithm can easily be
sufficient to make up for that difference.
Your advice to "avoid recursion, if at all possible" is an overreaction.
Kleuskes & Moos said:You're like a mechanic telling me how brakes are useless since they
cannot guarantee that you won't run into anything, anyway. Even when
applying the brakes, you can still run over a pedestrian or a 20-ton
truck, so basically brakes are useless.
Keith Thompson said:(I'm keeping this in comp.unix.programmer and comp.lang.c for now, since
it still seems relevant to both. Feel free to set followups if that
changes.)
Why? If a program finds it needs more memory, it can always call
malloc() again, or realloc() to increase the size of an existing block.
Can you give an example where it makes sense to allocate a large block
of memory and not use it (or use only a small initial portion of it)?
The problem is that if a data structure is inherently recursive thenThe only portable option (and it's been dubbed a kludge)
is to keep track of recursions manually and implement the damn buzzer
yourself. A better solution is to avoid that kind of situation in the
first place. Laying off recursion goes a long way of achieving that.
Kleuskes & Moos said:Ah... That's news. I was under the distinct impression that stack-
overflows are impossible to catch. Please expound on your method to
reliably (and portably) catch stack-overflows in recursive algorithms.
I'm quite curious.
Actaully the OOM-killer kills *some* process, not necessarily the one
that just tried to use allocated memory.
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.