A note on the void main() canard

S

spinoza1111

It is true that given the deficiencies of C, a void main() could break
a poorly-written OS.

If the OS expects a C program to return something, it probably has a
"stack" and expects this stack to increase by one as a result of
calling an executable C module. It can then safely pop this value and
pass it to a shell procedure for treatment as the return code.

If the procedure is void main(), this pop operation will damage or
even destroy the stack and create problems in the OS. For example, it
might cause the module which calls executables to return not to its
caller, but its caller's caller, with all sorts of bad things
happening.

It's not enough to say that the OS should record the size of the stack
and check after control returns from the executable for a stack size
of s+1; for in the general case, we know not where the abstract OS
could store this value. We are not, in the general scientific case,
able to assume that the executable caller has state (memory), and it
would be really, really stupid for the OS to save the size in what is
often the ONLY memory resource available to such "local" variables,
eg., the stack itself:

// ***** Really stupid code *****
int cExecutableCall(int intArgCount, char **ptrArgValue)
{
int intOldStackSize = stackSize();
main(intArgCount, ptrArgValue);
intRC = pop();
if (intOldStackSize != stackSize() + 1) comeWrack();
..
..
..
]

If main() is void, the pop() in the above will destroy
intOldStackSize, and come, wrack.

But properly understood, the compilability without showstopper error
of void main() is a gross and easily repaired bug in the C programming
language. It is allowed to "talk to" the OS and through it to shell
procedures, but it may send a poison pill in the form of a void main()
"message" which would (for example), give a mere shell procedure
access to a secure value.

Obviously, had the C99 and C89 standards geeks been men, they would
have fixed this problem. They could simply have legislated that all C
programs intended to run hosted would in the absence of a valid main
be given one.

Such a standard would have mandated what seems to me a simple
transformation:

void main()
{
printf("Hello world, I am a bonehead\n");
}

to

int _main(int argc, char **argv)
{
main();
return 0;
}
void main()
{
printf("Hello world, I am a bonehead\n");
}

where _main (or some suitable transformation of the name of main())
gets control.

The OS runtime can not be assumed to have either the complete "tuple"
of function name, return type and parameter list of the main(), nor
memory in which to remember the stack's size before the call of the
executable, therefore void main() programs are a security threat. But
it appears to me at this point that the C99 and C89 geeks, who seem to
have been selected from a mob of unqualified volunteers, had no
mandate to change C and thereby discommode vendors, who'd pleased Wall
Street by laying off senior, competent people able to make the above
change.

For void main() was not forbid outright, nor was it decided that the
coding of the main() procedure's header be taken out of the grubby
hands of mere C programmers, and they be forced to code something like

main
{
printf("Hello world, I am a bonehead\n");
}

where the keyword "main" would always expand to "int main(int argc,
char **argv), or

main(intArgumentCount, ptrArgumentValue)
{
printf("Hello world, I am a class act and can spell real wurdz\n");
}

where I give the programmer ONLY the ability to name the parameters,
and nothing more.

This would have upset the only "real" men...the money boys.

Instead, it's more fun to trash personal reputations while Wall Street
gets richer, Goldman Sachs uses incomprehensible and insecure C code
to make a mess of our future, and British Petroleum uses
incomprehensible and insecure C code to reassure the people of
Louisiana that "everything is under control".
 
S

Stargazer

But properly understood, the compilability without showstopper error
of void main() is a gross and easily repaired bug in the C programming
language.

Bug? Very interesting.
It is allowed to "talk to" the OS and through it to shell
procedures, but it may send a poison pill in the form of a void main()
"message" which would (for example), give a mere shell procedure
access to a secure value.

You can do that (hopefully) within the current standard:

#include <stdlib.h>
#include <stdio.h>

void send_a_poison_pill(void)
{
system("c:\\windows\system32\\cmd.exe -k \"echo I got a poison pill.
Give me access to a secure value now!!!\r\n\"");
}

void main()
{
if (atexit(send_a_poison_pill))
printf("Sorry, won't be able to send a poison pill\n");
exit(EXIT_SUCCESS);

// No return to caller
}
Obviously, had the C99 and C89 standards geeks been men, they would
have fixed this problem. They could simply have legislated that all C
programs intended to run hosted would in the absence of a valid main
be given one.

Such a standard would have mandated what seems to me a simple
transformation:

void main()
{
printf("Hello world, I am a bonehead\n");

}

to

int _main(int argc, char **argv)
{
main();
return 0;}

void main()
{
printf("Hello world, I am a bonehead\n");

}

where _main (or some suitable transformation of the name of main())
gets control.

The OS runtime can not be assumed to have either the complete "tuple"
of function name, return  type and parameter list of the main(), nor
memory in which to remember the stack's size before the call of the
executable, therefore void main() programs are a security threat. But
it appears to me at this point that the C99 and C89 geeks, who seem to
have been selected from a mob of unqualified volunteers, had no
mandate to change C and thereby discommode vendors, who'd pleased Wall
Street by laying off senior, competent people able to make the above
change.

Let's see what "senior, competent people" would need to do to satisfy
your request.

1) main() is just a function. While C allows variable parameters list
and main() could have been defined just as "int main(...)", it doesn't
allow "variable return types". Unlike parameters, for which a caller
may assume full responsibility, return types are at responsibility of
the callee, which your approach dismisses. If at add something like
"__unspecified_return_type" return type to the language, it should be
allowed for use by any function.

2) Program start-up code has nothing to do with OS per se. It's just a
small piece of code that is linked statically to the program. You may
possibly redefine main to be "void main()", but that would prohibit
"int main()" - you can't have start-up code call to both at the same
time.

3) C was designed with the intention that the language allows writing
"freestanding" programs so that they work the same on "hosted"
implementations as long as they don't use system-specific extensions.
You propose adding language semantic that can potentially break
freestanding programs which include use of main().

4) Compiler cannot know that if you didn't define a "correct main()"
you didn't define it also in all other modules that are linked-in.

5) "void main()" is not a "problem", it just doesn't have a defined
behavior. If a programmer encounters a problem with "undefined
behavior" and insists on his usage, he is responsible for making it
work. Not collectively compilers' and OS'es developers.

Finally, all your long voe has very short and simple solution within
the current standard, which "senior, competent people" definitely may
use :)

------------------ void_main_wrapper.c --------------------

#define main VOID_MAIN
#include "void_main_module.c"
#undef main

void VOID_MAIN(int argc, char **argv);

int main(int argc, char **argv)
{
VOID_MAIN(argc, argv);
return -32767; // This is not defined as well, but who cares
about that now
}

-------------------------------------------------------------
 
T

Tom St Denis

It is true that given the deficiencies of C, a void main() could break
a poorly-written OS.

<snip nonsense>

Generally if you are hosted there is no reason not to use int as the
return type. Exception possibly being a daemon application but even
then you might have to exit before you go resident. But even if you
don't do any fancy returns is adding "return 0;" so damn hard?

In embedded spaces where your main() never returns it's almost
universally safe to use void as the return type, and it probably saves
you a byte or two of code since there is no preparation of a return
value. In most deeply embedded spaces you typically have access to
the startup code so you could rename your C entry point
"omglulziamanentrypoint" if you want.

C isn't broken. You're just a psychopath who lacks experience
developing in C.

Tom
 
K

Kenny McCormack

<snip nonsense>

Generally if you are hosted there is no reason not to use int as the
return type. Exception possibly being a daemon application but even
then you might have to exit before you go resident. But even if you
don't do any fancy returns is adding "return 0;" so damn hard?

You do realize that you whole argument could be used to say that "void"
itself is unnecessary - and thus could/should be discarded - don't you?

Every where that someone writes: void noretval(...) { ... }
could just as easily be: int noretval(...) { ... }
as it was in classic C. And, again, as in classic C, anything that is
"void *" could/should be "char *". Note that the requirement that "void *"
and "char *" be, essentially, aliases for each other, makes this even
more clear.

Its funny how the regs go back and forth on this sort of thing. When it
suits their purpose, they say "Do things the minimalist way", but when
it suits their purpose to argue for gaudy, they don't shrink away from that.

--
(This discussion group is about C, ...)

Wrong. It is only OCCASIONALLY a discussion group
about C; mostly, like most "discussion" groups, it is
off-topic Rorsharch [sic] revelations of the childhood
traumas of the participants...
 
S

spinoza1111

<snip nonsense>

Generally if you are hosted there is no reason not to use int as the
return type.  Exception possibly being a daemon application but even
then you might have to exit before you go resident.  But even if you
don't do any fancy returns is adding "return 0;" so damn hard?

No. We're discussing how best to handle existing code, which should
have been the concern of the standard.
In embedded spaces where your main() never returns it's almost
universally safe to use void as the return type, and it probably saves
you a byte or two of code since there is no preparation of a return
value.  In most deeply embedded spaces you typically have access to
the startup code so you could rename your C entry point
"omglulziamanentrypoint" if you want.
Meaningless.



C isn't broken.  You're just a psychopath who lacks experience
developing in C.

I think that if that were true (which it isn't), it might be a good
thing, for in my experience, "developers" are corrupted by the "need"
to "get it done".
 
S

spinoza1111

Bug? Very interesting.


You can do that (hopefully) within the current standard:

#include <stdlib.h>
#include <stdio.h>

void send_a_poison_pill(void)
{
  system("c:\\windows\system32\\cmd.exe -k \"echo I got a poison pill.
Give me access to a secure value now!!!\r\n\"");

}

void main()
{
  if (atexit(send_a_poison_pill))
    printf("Sorry, won't be able to send a poison pill\n");
  exit(EXIT_SUCCESS);

  // No return to caller





}






Let's see what "senior, competent people" would need to do to satisfy
your request.

1) main() is just a function. While C allows variable parameters list
and main() could have been defined just as "int main(...)", it doesn't
allow "variable return types". Unlike parameters, for which a caller
may assume full responsibility, return types are at responsibility of
the callee, which your approach dismisses. If at add something like
"__unspecified_return_type" return type to the language, it should be
allowed for use by any function.

2) Program start-up code has nothing to do with OS per se. It's just a
small piece of code that is linked statically to the program. You may
possibly redefine main to be "void main()", but that would prohibit
"int main()" - you can't have start-up code call to both at the same
time.

3) C was designed with the intention that the language allows writing
"freestanding" programs so that they work the same on "hosted"
zzz...

implementations as long as they don't use system-specific extensions.
You propose adding language semantic that can potentially break
freestanding programs which include use of main().

I don't propose anything. I am merely showing that the issue of void
main() was one of those canards, directed against programmers, that
arises in the lack of ethics on the part of standards writers, here
standards writers with more care for compiler vendors than people.

If the standards monkeys had cared about actually making it possible
for a c main() to communicate with the operating system, they would
have included, as an alternative, a main() with a pointer to void
reference parameter:

int main(void *ptr)

But, all this is handled in C Sharp and Java with the Object type,
which unlike a void is a type and not a munged up mess.

4) Compiler cannot know that if you didn't define a "correct main()"
you didn't define it also in all other modules that are linked-in.
Incoherent.

5) "void main()" is not a "problem", it just doesn't have a defined

No, it does. It doesn't return anything. That's its "defined
behavior".
behavior. If a programmer encounters a problem with "undefined
behavior" and insists on his usage, he is responsible for making it
work. Not collectively compilers' and OS'es developers.

Finally, all your long voe has very short and simple solution within
the current standard, which "senior, competent people" definitely may
use :)

I've always noted that using the word "competent" in programming
circles creates ill-will, because the fact is that once programmers
become competent, they also evolve to the point where they leave for
Asia or open health food stores, because people with that level of
intelligence don't want to put up with corporate BS.

------------------ void_main_wrapper.c --------------------

#define main VOID_MAIN
#include "void_main_module.c"
#undef main

void VOID_MAIN(int argc, char **argv);

int main(int argc, char **argv)
{
   VOID_MAIN(argc, argv);
   return -32767;   // This is not defined as well, but who cares
about that now

}

Yeah, who gives a ****.
 
S

spinoza1111

You do realize that you whole argument could be used to say that "void"
itself is unnecessary - and thus could/should be discarded - don't you?

Every where that someone writes: void noretval(...) { ... }
could just as easily be: int noretval(...) { ... }
as it was in classic C.  And, again, as in classic C, anything that is
"void *" could/should be "char *".  Note that the requirement that "void *"
and "char *" be, essentially, aliases for each other, makes this even
more clear.

Its funny how the regs go back and forth on this sort of thing.  When it
suits their purpose, they say "Do things the minimalist way", but when
it suits their purpose to argue for gaudy, they don't shrink away from that.

....and after they've sung Hosannahs to "standard" code, one discovers
that their "standard" is such a mess that almost no C programs are
"strictly conformant".

They are Augustinians and Calvinists, who wind up restricting
Salvation to a vanishingly small set of predestined "elect" who can
write Perfect C, while to them we are headed for the Bad Fire.
--
(This discussion group is about C, ...)

Wrong.  It is only OCCASIONALLY a discussion group
about C; mostly, like most "discussion" groups, it is
off-topic Rorsharch [sic] revelations of the childhood
traumas of the participants...
 
T

Tom St Denis

...and after they've sung Hosannahs to "standard" code, one discovers
that their "standard" is such a mess that almost no C programs are
"strictly conformant".

They do what? I have no problem writing portable C code, but then
again, I'm good at what I do.

Tom
 
T

Tom St Denis

No. We're discussing how best to handle existing code, which should
have been the concern of the standard.

main() has been expected to return int for quite some time.
I think that if that were true (which it isn't), it might be a good
thing, for in my experience, "developers" are corrupted by the "need"
to "get it done".

I love how you act like there is a group of us "professionals" who are
conspiring against you. Really? Over C? Like what, you think there
are men with suits and shades who wander around "enforcing" C rules or
something?

Either you want to write code that is compliant or you don't. Nobody
is forcing you to do anything. If you want to write

float main(char *fuckyou, int ya_rly);

Then go for it. I personally don't give even the slightest bit more
than a ratass what you do.

Tom
 
K

Kenny McCormack

Tom St Denis said:
float main(char *fuckyou, int ya_rly);

Then go for it. I personally don't give even the slightest bit more
than a ratass what you do.

This may be hard for you to take, but I actually believe you.
No sensible person (on a Usenet newsgroup) *would* care what I do,
either in my personal or my professional lives, as long as it didn't
affect them, in *their* personal or my professional lives. And note
that it would be pretty damn hard (though not impossible, I suppose) to
imagine/construct a situation where it would have such an effect.

The above is certainly just "common sense". But, when you see the posts
made by Kiki and others like him, you really are left with the
impression that they really, really *do* care about what each and every
little person does. They simply can't leave anything unsaid. This is
creepy, and, quite frankly, a little scary. One can't help but wonder
how this situation came to be.

--
No, I haven't, that's why I'm asking questions. If you won't help me,
why don't you just go find your lost manhood elsewhere.

CLC in a nutshell.
 
T

Tom St Denis

The above is certainly just "common sense".  But, when you see the posts
made by Kiki and others like him, you really are left with the
impression that they really, really *do* care about what each and every
little person does.  

Nope, it's in your head.

If you post a falsehood in usenet they might [and probably would]
correct you. But if you want to believe a falsehood in your private
life I doubt they care.

So long and short of it is STFU unless you're actually right [or
asking a question].

Tom
 
K

Kenny McCormack

The above is certainly just "common sense".  But, when you see the posts
made by Kiki and others like him, you really are left with the
impression that they really, really *do* care about what each and every
little person does.  

Nope, it's in your head.

If you post a falsehood in usenet they might [and probably would]
correct you. But if you want to believe a falsehood in your private
life I doubt they care.

Oh, but they do. Not necessarily about me personally. I would hope
by now that Kiki has given up on reforming me.

But about the average Joe Newbie: Definitely.
So long and short of it is STFU unless you're actually right [or
asking a question].

Tom

I'm always right.

Never on topic, of course. But then again, nobody ever is (*).

(*) Except for the peculiar practice of language lawyering.

--
No, I haven't, that's why I'm asking questions. If you won't help me,
why don't you just go find your lost manhood elsewhere.

CLC in a nutshell.
 
S

Seebs

1) main() is just a function. While C allows variable parameters list
and main() could have been defined just as "int main(...)",

No, it couldn't -- you have to have at least one fixed argument.

It could have been defined as:
int main(int argc, ...);
with the rule being that the next argument would be of type "char **" or
something like that...
Unlike parameters, for which a caller
may assume full responsibility, return types are at responsibility of
the callee, which your approach dismisses. If at add something like
"__unspecified_return_type" return type to the language, it should be
allowed for use by any function.

And there are serious problems with that, because there are existing ABIs
in which you cannot do this.
5) "void main()" is not a "problem", it just doesn't have a defined
behavior. If a programmer encounters a problem with "undefined
behavior" and insists on his usage, he is responsible for making it
work. Not collectively compilers' and OS'es developers.

The funny thing is, Nilges is arguing this even though it's long since a
dead point -- even Schildt finally granted the point.

-s
 
S

spinoza1111

main() has been expected to return int for quite some time.



I love how you act like there is a group of us "professionals" who are
conspiring against you.  Really?  Over C?  Like what, you think there
are men with suits and shades who wander around "enforcing" C rules or
something?

No, they are destroying people.
Either you want to write code that is compliant or you don't.  Nobody

Actually, nobody here seems to be able to do that, by design.
 
S

spinoza1111

They do what?  I have no problem writing portable C code, but then
again, I'm good at what I do.

I'm better. Show us a real program that you claim is portable. Odds
are, given my experience with the regs like Seebach, that far from
being portable, your code is probably bugridden.
 
M

Malcolm McLean

Actually, nobody here seems to be able to do that, by design.
The problem is that, for almost every rule, there's a processor
architecture out there that makes it desperately inconvenient to
implement in a C compiler. For instance logical ops won't work as
expected if the machine doesn't use two's complement notation. Some
architectures don't like being asked to left-shift a register by more
than one less than the number of bits it contains. There's padding and
trap representations,. alignment issues, non-flat memory spaces,
achitectures where bytes are not octets. The response of the standard
drafters is to to call in "undefined behaviour", or "implementation-
defined behaviour", giving the implementation the freedom to comopile
code efficiently and easily. It creates an alm ost impossible task for
the programmer. A few months ago I challenged people to write a
completely portable tab expander. Someone (I think it was Richard
Heathfield) pointed out that one of the entries was non-compliant
because printf() isn't guaranteed to be able to print more than 126
characters in one go.

It's easy to identify the problem, much harder to solve it. The
alternative would be to force compilers for small architectures, which
tend to be the quirky ones, to emit inefficient code, or to blow up
the cost of compiler development. Neither of these are attractive
given C's typical users. Bascially we've got to live with 'good
enough' portability.
 
T

Tom St Denis

No, they are destroying people.

[citation needed]
Actually, nobody here seems to be able to do that, by design.

According to you, but I have long since questioned your ability to
develop software.

As for the rest of us professionals we write software that is used on
a variety of platforms with nary a portability problem. Not our fault
you suck.

Tom
 
M

Malcolm McLean

As for the rest of us professionals we write software that is used on
a variety of platforms with nary a portability problem.  Not our fault
you suck.
Of course a doctor would never say "you suck" to another doctor who
was, for instance, questioning the applicability of a treatment to
ethnic groups on whom it hadn't been tested, even if the objection was
patently unsound. Not would an lawyer say that to another lawyer who
was complaining, falsely, of inconsistent interpretations of some tax
regulations.

Not all professions are the same.
 
W

William Hughes

It is true that given the deficiencies of C, a void main() could break
a poorly-written OS.


Consider an OS that can launch an executable, only
communicates through a stack, and expects each executable
it launches to push a value onto the stack.

If the OS launches a badly behaved executable that does
not push a value onto the stack things can break.

[Note the OS can make things a lot more robust, by
pushing a sentinel value, e.g. 169, onto the stack,
always use to top value as the return value
and pop twice on return iff the top value is not
the sentinel value. Now things only break
if the executable pushes more than one value
or returns the sentinel value, and maybe not even then.]

What should a C implementation faced with void main()
do.

-it could refuse to produce an executable.

-it could produce a badly behaved executable

-it could produce a well behaved executable,
(maybe by wrapping main by bados_main, which
always returns a value, the value provided by
main() if it exists, otherwise 0. Note bados_main
may have to use implementation magic to determine
the return type of main)

I don't see the failure of the C standard to mandate the
third behaviour as a "deficiency".

- William Hughes
 
B

Ben Bacarisse

Malcolm McLean said:
The problem is that, for almost every rule, there's a processor
architecture out there that makes it desperately inconvenient to
implement in a C compiler. For instance logical ops won't work as
expected if the machine doesn't use two's complement notation.

Eh? Did you mean bit-wise ops?

Anyway, surely that depends on what is expected. If one expects a
operator to behave as it is defined to behave, one won't be surprised;
whereas expecting it to behave on all systems as it does on one is
simply a recipe for surprises. Saying "won't work as expected" suggests
a universal expectation.

<snip>
 

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

Similar Threads


Staff online

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top