Next: , Previous: , Up: Tutorial   [Contents][Index]


3.20 Runtime Errors

A runtime error is a special condition encountered during execution of the filter program, that makes further execution of the program impossible. There are two kinds of runtime errors: fatal errors, and uncaught exceptions. Whenever a runtime error occurs, mailfromd writes into the log file the following message:

RUNTIME ERROR near file:line: text

where file:line indicates approximate source file location where the error occurred and text gives the textual description of the error.

Fatal runtime errors

Fatal runtime errors are caused by a condition that is impossible to fix at run time. For version 9.0 these are:

Not enough memory

There is not enough memory for the execution of the program. Try to make more memory available for mailfromd or to reduce its memory requirements by rewriting your filter script.

Out of stack space; increase #pragma stacksize
Heap overrun; increase #pragma stacksize
memory chunk too big to fit into heap

These errors are reported when there is not enough space left on stack to perform the requested operation, and the attempt to resize the stack has failed. Usually mailfromd expands the stack when the need arises (see automatic stack resizing). This runtime error indicates that there were no more memory available for stack expansion. Try to make more memory available for mailfromd or to reduce its memory requirements by rewriting your filter script.

Stack underflow

Program attempted to pop a value off the stack but the stack was already empty. This indicates an internal error in the MFL compiler or mailfromd runtime engine. If you ever encounter this error, please report it to bug-mailfromd@gnu.org.ua. Include the log fragment (about 10-15 lines before and after this log message) and your filter script. See Reporting Bugs, for more information about bug reporting.

pc out of range

The program counter is out of allowed range. This is a severe error, indicating an internal inconsistency in mailfromd runtime engine. If you encounter it, please report it to bug-mailfromd@gnu.org.ua. Include the log fragment (about 10-15 lines before and after this log message) and your filter script. See Reporting Bugs, for more information about how to report a bug.

Programmatic runtime errors

These indicate a programmatic error in your filter script, which the MFL compiler was unable to discover at compilation stage:

Invalid exception number: n

The throw statement used a not existent exception number n. Fix the statement and restart mailfromd. See throw, for the information about throw statement and see Exceptions, for the list of available exception codes.

No previous regular expression

You have used a back-reference (see Back references), where there is no previous regular expression to refer to. Fix this line in your code and restart the program.

Invalid back-reference number

You have used a back-reference (see Back references), with a number greater than the number of available groups in the previous regular expression. For example:

  if $f matches "(.*)@gnu.org"
    # Wrong: there is only one group in the regexp above!
    set x \2
  …

Fix your code and restart the daemon.

Uncaught exceptions

Another kind of runtime errors are uncaught exceptions, i.e. exceptional conditions for which no handler was installed (See Exceptions, for information on exceptions and on how to handle them). These errors mean that the programmer (i.e. you), made no provision for some specific condition. For example, consider the following code:

prog envfrom
do
  if $f mx matches "yahoo.com"
    foo()
  fi
done

It is syntactically correct, but it overlooks the fact that mx matches may generate e_temp_failure exception, if the underlying DNS query has timed out (see Special comparisons). If this happens, mailfromd has no instructions on what to do next and reports an error. This can easily be fixed using a try/catch (see Catch and Throw) statement, e.g.:

prog envfrom
do
  try
  do
    if $f mx matches "yahoo.com"
      foo()
    fi
  done
  # Catch DNS errors
  catch e_temp_failure or e_failure
  do
    tempfail 451 4.1.1 "MX verification failed"
  done
done

Another common case are undefined Sendmail macros. In this case the e_macroundef exception is generated:

RUNTIME ERROR near foo.c:34: Macro not defined: {client_adr}

These can be caused either by misspelling the macro name (as in the example message above) or by failing to export the required name in Sendmail milter configuration (see exporting macros). This error should be fixed either in your source code or in sendmail.cf file, but if you wish to provide a special handling for it, you can use the following catch statement:

catch e_macroundef
do
  …
done

Sometimes the location indicated with the runtime error message is not enough to trace the origin of the error. For example, an error can be generated explicitly with throw statement (see throw):

RUNTIME ERROR near match_cidr.mfl:30: invalid CIDR (text)

If you look in module match_cidr.mfl, you will see the following code (line numbers added for reference):

23 func match_cidr(string ipstr, string cidr)
24   returns number
25 do
26   number netmask
27
28   if cidr matches '^(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9][0-9]?)'
29     return inet_aton(ipstr) & len_to_netmask(\3) = inet_aton(\1)
30   else
31     throw invcidr "invalid CIDR (%cidr)"
32   fi
33   return 0
34 done

Now, it is obvious that the value of cidr argument to match_cidr was wrong, but how to find the caller that passed the wrong value to it? The special command line option --stack-trace is provided for this. This option enables dumping stack traces when a fatal error occurs. Traces contain information about function calls. Continuing our example, using the --stack-trace option you will see the following diagnostics:

RUNTIME ERROR near match_cidr.mfl:30: invalid CIDR (127%)
mailfromd: Stack trace:
mailfromd: 0077: match_cidr.mfl:31: match_cidr
mailfromd: 0096: test.mfl:13: bar
mailfromd: 0110: mailfromd.mfl:18: foo
mailfromd: Stack trace finishes
mailfromd: Execution of the configuration program was not finished

Each trace line describes one stack frame. The lines appear in the order of most recently called to least recently called. Each frame consists of:

  1. Value of the program counter at the time of its execution;
  2. Source code location, if available;
  3. Name of the function called.

Thus, the example above can be read as: “the function match_cidr was called by the function bar in file test.mfl at line 13. This function was called from the function bar, in file test.mfl at line 13. In its turn, bar was called by the function foo, in file mailfromd.mfl at line 18”.

Examining caller functions will help you localize the source of the error and fix it.

You can also request a stack trace any place in your code, by calling the stack_trace function. This can be useful for debugging.


Next: , Previous: , Up: Tutorial   [Contents][Index]