[comp.lang.c] Check for function results

I1090801%DBSTU1.BITNET@CUNYVM.CUNY.EDU (11/25/87)

I am a student of computer science and I have to write a C-compiler.
The problem I came across is: does a C-compiler have to generate code
to check if a function really delivers a result in all cases?
Example: In the following (nonsense) function
   int f()
   {
        int a;
        a = 1;              /* only to set a to a non-garbage value */
        if (...)
             return a;
        else
             ...            /* statements without any return */
   }
a value is delivered in the then part but in the else part nothing
happens and the program just runs out of the end of the function.
So, in this case, some garbage is delivered. In this example you can
easily see this, but things get worse if the function is more
complicated. I think it isn't easy for a compiler to see all this
at compile-time, so things should be checked during runtime of a
program. My idea is to generate code that sets an internal flag
to FALSE at the start of the function. Each return(expression) should
set this flag to TRUE and then jump to the end of the function where
the return is handled. Here the flag should be checked and an error-
message be generated if it is still FALSE. This way it can be deteced
if the way through the function passed a return(expression).
I wonder if all this is really necessary, but I can't find anything
about this problem in K&R. Do other compilers check this? I think,
some strange errors can be detected by this method.

Maybe someone on the net can help me.

                                      Ulf Gruene
                                I1090801@DBSTU1.BITNET
                         Technische Universitaet Braunschweig
                                     West Germany

firth@sei.cmu.edu.UUCP (11/25/87)

In article <10530@brl-adm.ARPA> I1090801%DBSTU1.BITNET@CUNYVM.CUNY.EDU writes:
 I am a student of computer science and I have to write a C-compiler.
 The problem I came across is: does a C-compiler have to generate code
 to check if a function really delivers a result in all cases?
 Example: In the following (nonsense) function
    int f()
    {
         int a;
         a = 1;              /* only to set a to a non-garbage value */
         if (...)
              return a;
         else
              ...            /* statements without any return */
    }
 a value is delivered in the then part but in the else part nothing
 happens and the program just runs out of the end of the function.
 So, in this case, some garbage is delivered. In this example you can
 easily see this, but things get worse if the function is more
 complicated. I think it isn't easy for a compiler to see all this
 at compile-time, so things should be checked during runtime of a
 program. My idea is to generate code that sets an internal flag
 to FALSE at the start of the function. Each return(expression) should
 set this flag to TRUE and then jump to the end of the function where
 the return is handled. Here the flag should be checked and an error-
 message be generated if it is still FALSE. This way it can be deteced
 if the way through the function passed a return(expression).
 I wonder if all this is really necessary, but I can't find anything
 about this problem in K&R. Do other compilers check this? I think,
 some strange errors can be detected by this method.

Well, a C compiler probably doesn't have to check ANYTHING!  In addition,
this check is not necessarily a good one to put in: it is legal to call a
C function and throw away the result, so, who knows, maybe every call that
bypasses a return statement is one that doesn't want the result.

However, if you do put the check in, there is a much simpler mechanism:
have the return statements all execute a proper return, and plug the end
of the function body with your error code.  That is essentially free: you
execute no extra code to do the check.  A typical implementation might
look like this:

	f: ; procedure entry sequence

	   ...
	   ; return a

	   move a into R0
	   jump to exitlabel

	   ...

	    ; end of function
	   goto NO_RETURN_VALUE_ERROR

	exitlabel:
	   ; normal return sequence goes here

I assume you know enough to hoist that code at exitlabel if there is only
one return statement in the function.  (To do that is one pass: generate
the exit code at the point of the first return statement, and if necessary
jump back to it.)

gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/26/87)

In article <10530@brl-adm.ARPA> I1090801%DBSTU1.BITNET@CUNYVM.CUNY.EDU writes:
>... I think it isn't easy for a compiler to see all this
>at compile-time, ...

No, whether or not a function execution ends with an explicit
"return <expression>;" statement is not difficult to determine
at compile time, and all such statically-determinable usage
errors should be detected by the compiler/linker, not at run
time.

Producing a correct implementation of C from scratch is a
difficult project; it is much better for most purposes to
port some version of AT&T's Portable C Compiler than to have
to rediscover all the details of how to compile the language.
If the goal is an ANSI/ISO conformant implementation of C, I
would say it's too big a project for one person.

dag@chinet.UUCP (Daniel A. Glasser) (11/26/87)

In article <10530@brl-adm.ARPA> I1090801%DBSTU1.BITNET@CUNYVM.CUNY.EDU writes:
>I am a student of computer science and I have to write a C-compiler.
>The problem I came across is: does a C-compiler have to generate code
>to check if a function really delivers a result in all cases?
[Lots of stuff deleted]
>I wonder if all this is really necessary, but I can't find anything
>about this problem in K&R. Do other compilers check this? I think,
>some strange errors can be detected by this method.
>
>Maybe someone on the net can help me.
>
>                                      Ulf Gruene

Well, Ulf, maybe I can help you -- K&R explicitly covers this in chapter 4.
In section 1 (Basics) (in my book, it's page 68) there is the following:
(Reproduced without permission)

     "The return statement is the mechanism for returning a value from
    the called function to its caller.  Any expression can follow return:

	return ( expression )

    The calling function is free to ignore the returned value if it wishes.
    Furthermore, there need be no expression after return; in that case, no
    value is returned to the caller.  Control also returns to the caller with
    no value when execution "falls off the end" of the function by reaching
    the closing right brace.  It is not illegal, but probably a sign of
    trouble, if a function returns a value from one place and no value from
    another.  In any case, the "value" of a function which does not return
    one is certain to be garbage.  The C verifier lint checks for such errors.

The scheme that you propose introduces a large amount of overhead.
The compiler knows when it is transfering control to the function
epilogue (return) code, and knows how it gets there.  You could make
the compiler generate a warning (if the function is not declared void)
if you like.

The ANSI draft standard covers the return statement in section 3.6.6.4.
The text of that portion is (also quoted without permission):

   3.6.6.4  The return statement

   Constraints

	A return statement with an expression shall not  appear
   in a function whose return type is void.

   Semantics

	A return statement terminates execution of the  current
   function  and returns control to its caller.  A function may
   have any number  of  return  statements,  with  and  without
   expressions.

	If a return statement with an expression  is  executed,
   the  value  of the expression is returned to the caller.  If
   the expression  has  a  type  different  from  that  of  the
   function  in which it appears, it is converted as if it were
   assigned to an object of that type.

	If  a  return  statement  without   an  expression   is
   executed,  and the value of the function call is used by the
   caller, the behavior is  undefined.   Reaching  the  }  that
   terminates  a  function  is equivalent to execution a return
   statement without an expression.

I hope that this information helps.  Remember structure passing,
returns and assignment, enumerated types and pointers to void.
Otherwise, only 90% of the C code in the world will work with
your compiler.
						Daniel A. Glasser

Disclaimer:

   The contents of this posting are subject to change without notice.
   void where prohibited by law.  int everywhere else.
   The above is not the truth.  I don't know the truth.
-- 
					Daniel A. Glasser
					...!ihnp4!chinet!dag
					...!ihnp4!mwc!dag
					...!ihnp4!mwc!gorgon!dag
	One of those things that goes "BUMP!!! (ouch!)" in the night.

eao@anumb.UUCP (e.a.olson) (12/03/87)

In article <10530@brl-adm.ARPA> I1090801%DBSTU1.BITNET@CUNYVM.CUNY.EDU writes:
>I am a student of computer science and I have to write a C-compiler.
>The problem I came across is: does a C-compiler have to generate code
>to check if a function really delivers a result in all cases?
>Example: In the following (nonsense) function

    I seem to remember bing told in school, that in the absence of
    an explicit return, the return value would be the last expression
    evaluated in the function.  But I've never heard anything otherwise
    on the subject and it seems awfully implementation-dependent.