int main(void) { return main(); }

A

Army1987

Is that in the object line a conforming program?
If so, why?
If not, why?
I'd expect it to be much like
int main(void)
{
for (;;);
}

But if I compile it with lcc-win32 and run it in its rundos.exe, it says the
program exits with a return value of -1073741819 (i.e. -2^30 + 5) after
0.032 seconds or so. Why?

--
#include <stdio.h>
#include <stdlib.h>
int main(void) /* Don't try this at home */ {
const size_t dim = 256; int i;
for (i=0; malloc(dim); i++) /*nothing*/ ;
printf("You're done! %zu\n", i*dim);
puts("\n\n--Army1987"); return 0;
}
 
E

Eric Sosman

Army1987 wrote On 03/29/07 14:31,:
Is that in the object line a conforming program?

You mean "subject" line, and it's a bad place for
questions.
If so, why?

Because it satisfies the definition of "conforming
program" in Section 4, paragraph 7.
If not, why?

See above.
I'd expect it to be much like
int main(void)
{
for (;;);
}

But if I compile it with lcc-win32 and run it in its rundos.exe, it says the
program exits with a return value of -1073741819 (i.e. -2^30 + 5) after
0.032 seconds or so. Why?

Probably because the program exceeded an implementation
limit. Which limit? The Standard doesn't say, but the lists
in Section 5.2.4 do not claim to be exhaustive. (See also
Section 1, paragraph 2, point 5).
 
U

user923005

Is that in the object line a conforming program?
If so, why?
If not, why?
I'd expect it to be much like
int main(void)
{
for (;;);

}

But if I compile it with lcc-win32 and run it in its rundos.exe, it says the
program exits with a return value of -1073741819 (i.e. -2^30 + 5) after
0.032 seconds or so. Why?

--
#include <stdio.h>
#include <stdlib.h>
int main(void) /* Don't try this at home */ {
const size_t dim = 256; int i;
for (i=0; malloc(dim); i++) /*nothing*/ ;
printf("You're done! %zu\n", i*dim);
puts("\n\n--Army1987"); return 0;



}

Eric answered your question, and I have a guess about the why part.
Probably, since each call has to store the return address, you ran out
of automatic storage.
 
L

Lew Pitcher

Eric answered your question, and I have a guess about the why part.
Probably, since each call has to store the return address, you ran out
of automatic storage.

It is more likely that the loop
for (i=0; malloc(dim); i++) /*nothing*/ ;
exhausted available 'heap' memory, and the system (what-ever that is
wrt CLC <wink>) forcibly terminated the program.

To the OP: My bet is that, if you dig deep enough, you will find some
documentation on returncodes that tells you how to determine what a
"return value of -1073741819" actually means, and that documentation
will lead you to a "memory exhausted" error termination.

HTH
 
A

Army1987

Lew Pitcher said:
It is more likely that the loop
for (i=0; malloc(dim); i++) /*nothing*/ ;
exhausted available 'heap' memory, and the system (what-ever that is
wrt CLC <wink>) forcibly terminated the program.

I guess he was referring to the program in the object line, not to that in
the signature.

<ot>
BTW, I tried something very similar to that (signature) on a terminal logged
on a workstation (running on CentOS) at university, and in a short time it
raised an exception such as "Panic in 5 seconds" or something like that,
crashing the server and receiving curses from the other users who were
logged. A professor was sent to reboot the server as nobody else knew where
it was physically located. (Actually, I didn't expect that the OS *actually*
permitted me to do so rather than killing the process or making the malloc
return NULL. Taking into account that I didn't even have root privileges...)
On my PC, on Linux, if dim is small (i.e. below 2^15 or so) it makes the
system slow down more and more, and on a system monitor it seems that *all*
or almost RAM and swap partition are used, then the process is killed and
the memory released. Instead, if dim is large (2^16 or more), it prints an
unrealistic resullt of almost 3GB ("unrealistic" because I have 1 GB of RAM
and 1 GB of swap space) after less than a second. On Windows, a small dim
does apparently nothing different than for(;;); (but maybe I wasn't patient
enough), and a large dim prints a result of almost 2 GB.
</ot>
 
A

Army1987

Probably because the program exceeded an implementation
limit. Which limit? The Standard doesn't say, but the lists
in Section 5.2.4 do not claim to be exhaustive. (See also
Section 1, paragraph 2, point 5).

This means that I could write a compiler which doesn't support more than n
nested function calls, with n = 1 (that'd mean that you couldn't call any
function from within main...), and still call that a conforming
implementation? ;-)
 
B

Beej Jorgensen

Army1987 said:
This means that I could write a compiler which doesn't support more
than n nested function calls, with n = 1 (that'd mean that you couldn't
call any function from within main...), and still call that a
conforming implementation? ;-)

Even though I can't see that it's strictly against the standard, that
implementation would certainly violate the spirit of c99 6.5.2.2p11:

# Recursive function calls shall be permitted, both directly and
# indirectly through any chain of other functions.

I was a little surprised to not see a minimum limit on the function call
depth, though. Am I just missing it?

-Beej
 
U

user923005

Even though I can't see that it's strictly against the standard, that
implementation would certainly violate the spirit of c99 6.5.2.2p11:

# Recursive function calls shall be permitted, both directly and
# indirectly through any chain of other functions.

I was a little surprised to not see a minimum limit on the function call
depth, though. Am I just missing it?

-Beej

Perhaps it can be inferred from:

"5.2.4.1 Translation limits

[#1] The implementation shall be able to translate and
execute at least one program that contains at least one
instance of every one of the following limits:12)

-- 127 nesting levels of blocks"

Since each function call must necessarily enter a new block.
 
E

Eric Sosman

Beej Jorgensen wrote On 03/29/07 17:39,:
Even though I can't see that it's strictly against the standard, that
implementation would certainly violate the spirit of c99 6.5.2.2p11:

# Recursive function calls shall be permitted, both directly and
# indirectly through any chain of other functions.

I was a little surprised to not see a minimum limit on the function call
depth, though. Am I just missing it?

It's not there. One difficulty, I imagine, is in coming
up with an architecture-neutral way to describe the "weight"
of a function invocation. On many implementations it is
significantly cheaper to call a void function of one simple
argument that uses two auto variables than to call a struct-
valued function of forty arguments using ninety auto variables,
several of them being three-dimensional VLAs. But how do you
express that cost in a way that leads to a prescription of how
many nesting levels are usable?
 
K

Keith Thompson

user923005 said:
Even though I can't see that it's strictly against the standard, that
implementation would certainly violate the spirit of c99 6.5.2.2p11:

# Recursive function calls shall be permitted, both directly and
# indirectly through any chain of other functions.

I was a little surprised to not see a minimum limit on the function call
depth, though. Am I just missing it?

-Beej

Perhaps it can be inferred from:

"5.2.4.1 Translation limits

[#1] The implementation shall be able to translate and
execute at least one program that contains at least one
instance of every one of the following limits:12)

-- 127 nesting levels of blocks"

Since each function call must necessarily enter a new block.

I don't think so. I think that refers to the number of physically
nested blocks in the source program, not to the depth during
execution.
 
K

Keith Thompson

Eric Sosman said:
Beej Jorgensen wrote On 03/29/07 17:39,:

It's not there. One difficulty, I imagine, is in coming
up with an architecture-neutral way to describe the "weight"
of a function invocation. On many implementations it is
significantly cheaper to call a void function of one simple
argument that uses two auto variables than to call a struct-
valued function of forty arguments using ninety auto variables,
several of them being three-dimensional VLAs. But how do you
express that cost in a way that leads to a prescription of how
many nesting levels are usable?

By adding the following to C99 5.2.4.1:

-- 127 nesting levels of function calls

But all the limits in 5.2.4.1 are primarily translation-time limits;
an implementation that failed to meet one of them would probably do so
by blowing up during compilation. The closest thing to a run-time
limit is 65535 bytes in an object, and even that is something that the
compiler has too keep track of during compilation (except for
dynamically allocated objects).

A required minimum number of nested function calls, on the other hand,
would be something that would only affect program execution, and it
would depend on the resources available during program execution.

Perhaps there should be a separate set of required limits for run-time
capacity.
 
E

Eric Sosman

Keith said:
By adding the following to C99 5.2.4.1:

-- 127 nesting levels of function calls

... which expresses a requirement for nesting levels, but
completely ignores the "weight" or "cost" of a call.

int f(int depth) {
char broiled[65535] = { 0 };
char ming[65535] = { 1 };
char shu_ding[65535] = { 2 };
... about fifty MB worth of auto variables ...
return (depth <= 126) ? 42
: broiled[f(depth+1)%65535]
+ ming[f(depth+2)%65535]
+ shu_ding[f(depth+3)%65535]
+ ... ;
}

It seems to me that an implementation that guaranteed correct
evaluation of foo(0) might be able to guarantee little else ...
Perhaps there should be a separate set of required limits for run-time
capacity.

Perhaps. But (I repeat) see Section 1, paragraph 2, point 5.
 
C

CBFalconer

Lew said:
It is more likely that the loop
for (i=0; malloc(dim); i++) /*nothing*/ ;
exhausted available 'heap' memory, and the system (what-ever
that is wrt CLC <wink>) forcibly terminated the program.

No forcible termination. It just ended, and due to the abysmally
stupid failure to return a valid value from main the result is
undefined.
 
K

Keith Thompson

Eric Sosman said:
... which expresses a requirement for nesting levels, but
completely ignores the "weight" or "cost" of a call.
[snip]

Yes, it does. I can't think of any good way to express such a
requirement; the point would be to require the implementation to
accept *some* program that produces 127 levels of function calls.
(BTW, the wording could be clearer; it's intended to refer to the
depth of the "call stack", not to something like
f1(f2(f3(f4(...f127()...)))).)

I think main point of the translation limits in 5.2.4.1 isn't so much
to require those specific values (though that's part of it), but to
discourage imposing specific limits at all. For example, a compiler
must support (at least one program that contains) at least 127
arguments in one function call. The easiest way to satisfy that
requirement isn't to use a fixed-size 127-element table; it's to
handle arguments dynamically, limiting them only by amount of memory
available during compilation.

A requirement to allow 127 levels of function calls, if it were added
to the standard, would forbid an implementation that only allows 1
level.
It seems to me that an implementation that guaranteed correct
evaluation of foo(0) might be able to guarantee little else ...


Perhaps. But (I repeat) see Section 1, paragraph 2, point 5.

Which says:

This International Standard does not specify
[...]
-- the size or complexity of a program and its data that will
exceed the capacity of any specific data-processing system or
the capacity of a particular processor

And yet it requires a hosted implementation to support 65535 bytes in
an object.
 
L

Lew Pitcher

... snip ...
^
Lookee here----------------------/
No forcible termination. It just ended, and due to the abysmally
stupid failure to return a valid value from main the result is
undefined.

Chuck, it appears that you didn't notice the
return 0;
in the OPs code for main()

I didn't see any way for the code to avoid that statement, so it
appears that main() /does/ return a valid value.
 
D

Daniel Rudy

At about the time of 3/29/2007 11:31 AM, Army1987 stated the following:
Is that in the object line a conforming program?
If so, why?
If not, why?
I'd expect it to be much like
int main(void)
{
for (;;);
}

The above questions have already been answered by another poster, so
I'll leave that part of it alone.
But if I compile it with lcc-win32 and run it in its rundos.exe, it says the
program exits with a return value of -1073741819 (i.e. -2^30 + 5) after
0.032 seconds or so. Why?

It's probably undefined behavior which means that it's implementation
specific. FWIW, on my system, the program ran until I got a memory
fault and the core dropped.

strata:/home/dr2867/c/test 1051 $$$ ->./ub003
Memory fault (core dumped)
strata:/home/dr2867/c/test 1052 $$$ ->ls -l
total 69586
-rwxr-xr-x 1 dr2867 users 7195 Mar 29 21:29 ub003
-rw-r--r-- 1 dr2867 users 47 Mar 29 21:28 ub003.c
-rw------- 1 dr2867 users 67309568 Mar 29 21:29 ub003.core
strata:/home/dr2867/c/test 1052 $$$ ->

The program that you gave:

int main(void) { return main(); }

is an infinite recursive loop. It will run until the stack blows up.
Which is what happened in my case. As to why you got a return value,
that's implementation specific: aka undefined behavior.


--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
D

Daniel Rudy

At about the time of 3/29/2007 12:52 PM, Army1987 stated the following:
I guess he was referring to the program in the object line, not to that in
the signature.

<ot>
BTW, I tried something very similar to that (signature) on a terminal logged
on a workstation (running on CentOS) at university, and in a short time it
raised an exception such as "Panic in 5 seconds" or something like that,
crashing the server and receiving curses from the other users who were
logged. A professor was sent to reboot the server as nobody else knew where
it was physically located. (Actually, I didn't expect that the OS *actually*
permitted me to do so rather than killing the process or making the malloc
return NULL. Taking into account that I didn't even have root privileges...)

LOL

What was the fallout from that? Considering that you weren't even root,
did they know it was you who did it?

Most modern operating systems that use memory protection are protected
enough so if a program goes out of control, the OS kills it in short
order. Even programs ran under UID 0 (root) can't really crash the
system on their own. Now something like

dd if=/dev/random of=dev/kmem bs=1024

will kill the system in short order.

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 
C

CBFalconer

Lew said:
^
Lookee here----------------------/


Chuck, it appears that you didn't notice the
return 0;
in the OPs code for main()

I didn't see any way for the code to avoid that statement, so it
appears that main() /does/ return a valid value.

Woops. My second mistake this year. Things are getting bad.

That leaves something foolish in lcc-win32.
 
D

Daniel Rudy

At about the time of 3/29/2007 4:20 PM, Keith Thompson stated the following:
By adding the following to C99 5.2.4.1:

-- 127 nesting levels of function calls

But all the limits in 5.2.4.1 are primarily translation-time limits;
an implementation that failed to meet one of them would probably do so
by blowing up during compilation. The closest thing to a run-time
limit is 65535 bytes in an object, and even that is something that the
compiler has too keep track of during compilation (except for
dynamically allocated objects).

A required minimum number of nested function calls, on the other hand,
would be something that would only affect program execution, and it
would depend on the resources available during program execution.
Exactly.

Perhaps there should be a separate set of required limits for run-time
capacity.

Um...no.

How are you going to account for a program that runs on a super
computer? One that uses 25GB Ram, 50 CPUs, and other resources? You
can't. A program cannot use more resources than the system has
available, period. Eventually, you will run out of something...disk
space, memory, CPU utilization, Network bandwidth, etc. Even swap is
only so big. IMO, system imposed resource limits are good way to go.

--
Daniel Rudy

Email address has been base64 encoded to reduce spam
Decode email address using b64decode or uudecode -m

Why geeks like computers: look chat date touch grep make unzip
strip view finger mount fcsk more fcsk yes spray umount sleep
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top