Yeah, the second trap wasn't working correctly as I expected it to work, regardless of whether I had it in there or I removed it. After poking at it a bit more, and having a better understanding of things, I think I have a final solution. Hopefully this new version of the demonstration script will make it more clear.

In particular, your notes were very helpful in making me understand this more clearly:

- $BASHPID was very important. I'd seen it in my google search results, but hadn't seen anyone clearly explain that it would get me the PID of the current function being called, in my situation. Everyone described it differently. In particular, everyone in my google search results seemed to indicate that I needed to use "$!" to get that value that I was looking for, and that $BASHPID would get me something completely different. Now that I know the right value to use, it helped immensely.

- Understanding that the KILL signal didn't kill anything, and that I still needed an "exit 1" after the kill, was super-critical to getting the code to work right for me. I now see that the KILL signal does not interrupt the program flow of the child. It only executes the trap code after the child process has exited. I expected it to terminate things right away, and it doesn't work like that. For this reason, I still need that trap defined inside the sub function. My only problem before was that the trap was mis-coded, it needed that $BASHPID and some other tricks before it could work right.


Here's my updated example script which hopefully shows clearly how it all works now. Thanks again, everyone, for your excellent help and clear explanations.

Code:
#!/bin/bash

# ----------------------------------------------
# Bash - How to fully exit a program from within
# a function which returns data to the caller.
# ----------------------------------------------
# Program to demonstrate an issue with Bash.
# The problem is: You want to write a function
# which can either:
#   - Return data to the caller.
#   - Or exit the script completely if it
#     discovers some kind of a problem.
# The problem is that Bash can't do both. You can
# only exit the script if you are at the top level
# or you're inside a function where the call to the
# function doesn't try to retrieve data from it.
# You can't do "variable=$( function )" if the
# function wants to maybe exit the script. The
# reason is that when you use the "$( function )"
# syntax, it's actually launching a whole
# separate Bash script process to run the
# function, so "exit 1" only exits that function.
#
# This program demonstrates the problem and the
# work-around.

# ----------------------------------------------
# Work-around is here
# ----------------------------------------------
# These lines are part of a work-around to the
# problem that this program demonstrates. This
# was obtained from the following StackOverflow
# question:
# https://stackoverflow.com/questions/9893667/is-there-a-way-to-write-a-bash-function-which-aborts-the-whole-execution-no-mat
# Instead of relying on "exit 1" to exit the function,
# create trap and trigger the trap from within the
# function. The trap executes the code block within
# the quotes when it recieves a TERM signal. It 
# executes this code block from the context of the
# top level of the script, outside the function.
# To accomplish this, we also need to set an
# environment variable based on "$$" which gets
# us the scripts's PID so that we know where to
# send that TERM signal when the time comes.
# To trigger the trap, use the command
# "kill -s TERM $TOP_PID" inside the function
# where you want to exit the program. 
trap "echo TOPEXIT >&2 && exit 1" TERM
export TOP_PID=$$    
echo "The top level PID is $TOP_PID" >&2


# ----------------------------------------------
# Function: Test for a problem using a parent
# function. If there is no problem, then call a 
# child function. Also gather some data and return
# it. If there is any problem, exit the program.
# ----------------------------------------------
TestForParentProblem()
{
  # Secondary work-around for a child function.
  # When trapping inside a child function,
  # you must chain up another signal to the
  # from the child, to here, and on to the parent
  # level trap in order to get a proper kill.
  # If you don't do this, and you send the signal
  # from the child all the way to the top level
  # (skipping a trap here in this function), then
  # this function will still execute to its end,
  # hitting instructions you don't want it to hit.
  # This secondary work around must send a signal to
  # the top-level PID and exit, in this context here
  # inside this function, in order to stop the
  # execution of the code inside this function.
  # Note that $BASHPID gets us this function's PID
  # so that the signal coming up from the child can
  # go to the correct place here.
  trap "echo SUBEXIT >&2 && kill -s TERM $TOP_PID && exit 1" TERM
  export PARENT_PID=$BASHPID  
  echo "The parent function PID is $PARENT_PID" >&2

  echo "Testing for a potential parent problem..."  >&2
  if "$parentProblem" = true
  then
    echo "There was a parent problem. Exiting program now." >&2

    # ----------------------------------------------
    # MAIN BUG CAN BE DEMONSTRATED HERE
    # ----------------------------------------------
    # The goal is to exit the script at this point,
    # but "exit 1" does not work as expected here.
    # TO DEMONSTRATE THE PROBLEM, UNCOMMENT
    # THIS LINE OF THE SCRIPT AND RUN IT.
    #   exit 1
    # Instead, to fix the problem, invoke the special
    # trap (created above) to exit the script at the
    # main level instead of from within this lower
    # level function. Here is the work-around:
    echo "Sending kill signal to top level PID $TOP_PID" >&2
    kill -s TERM $TOP_PID
    exit 1 
    # Those lines combined with the trap above, works
    # around the problem. NOTE: We must still do an Exit 1
    # above, to prevent the rest of the function from
    # continuing while we wait for the trap to trigger.
    
    # Check for bug.
    echo "----------------------------------------------------------------" >&2
    echo "BUG PARENT 1: If you can read this, the program did not exit."    >&2
    echo "----------------------------------------------------------------" >&2
  else
    echo "No parent problem found." >&2
  fi
  
  # Test to see if the workaround succeeds in a child routine.
  returnFromSubTest=$( SubTestForProblem )
  echo "Returned Data from child function was: $returnFromSubTest" >&2

  if "$subProblem" = true
  then
    echo "----------------------------------------------------------------" >&2
    echo "BUG CHILD 2: If you can read this, the program did not exit."     >&2
    echo "----------------------------------------------------------------" >&2   
  fi

  echo "Returning data from parent function." >&2
  returnData="Some_Parent_Data"
  echo $returnData
}


# ----------------------------------------------
# Function: Sub-test for a problem and kill the
# program if there is a problem. This will be
# called as a child sub-function from the 
# TestForParentProblem function.
# ----------------------------------------------
SubTestForProblem()
{
  echo "SubTesting Now (child subroutine called from parent subroutine)..."  >&2
  if "$subProblem" = true
  then
    echo "There was a subtest problem. Exiting program." >&2

    # ----------------------------------------------
    # SECONDARY BUG CAN BE DEMONSTRATED HERE
    # ----------------------------------------------
    # The goal is to exit the script at this point,
    # using the KILL signal workaround, but even that fails
    # us here. If the work-around is working as I expect it
    # to work, the program should be killed from the child
    # function just as effectively as if I had killed it from
    # the parent function. However, there is still a problem.
    # Because the KILL is just a signal, the parent function
    # continues to finish executing if you send a KILL signal
    # to it from within the child function. So, for example,
    # you cannot do this here and have it work as expected: 
        # echo "Sending kill signal to top level PID $TOP_PID" >&2
        # kill -s TERM $TOP_PID
        # exit 1
    # The above does not work and the parent function continues
    # executing commands even after you sent the KILL. So
    # instead, you have to daisy chain the KILLs up from child
    # to parent. There is a separate TERM trap defined for the
    # sub function in the parent function. Invoke it here to
    # work around the problem:
    echo "Sending kill signal to parent function PID $PARENT_PID" >&2
    kill -s TERM $PARENT_PID
    exit 1
    
    # Check for bug.
    echo "----------------------------------------------------------------" >&2
    echo "BUG CHILD 1: If you can read this, the program did not exit."     >&2
    echo "----------------------------------------------------------------" >&2      
  else
    echo "No sub problem found." >&2
  fi
  
  # Return data from the function.
  echo "Returning data from sub function." >&2
  subReturnData="Some_Child_Data"
  echo $subReturnData
}


# ----------------------------------------------
# Main program code body
# ----------------------------------------------
echo "Starting tests now."  >&2

# ----------------------------------------------
# Baseline test - There should be no problem and
# it should return data from both functions.
# ----------------------------------------------
echo "" >&2
echo "Baseline test - No problems in either parent function or child function." >&2
parentProblem=false
subProblem=false
returnedData=$( TestForParentProblem )
echo "Returned Data from parent function was: $returnedData" >&2

# ----------------------------------------------
# Test child routine - Try exiting during
# the child subroutine. It should stop executing
# code from both the child function and its
# parent function.
#
# NOTE: COMMENT THIS SECTION OUT IF YOU WANT TO
# TEST THE PARENT TEST BELOW.
# ----------------------------------------------
echo "" >&2
echo "Child subroutine test - Problem in child function but not in parent function." >&2
parentProblem=false
subProblem=true
returnedData=$( TestForParentProblem )
echo "Returned Data from parent function was: $returnedData" >&2
echo "----------------------------------------------------------------" >&2
echo "BUG MAIN 1: If you can read this, the program did not exit."      >&2
echo "----------------------------------------------------------------" >&2  

# ----------------------------------------------
# Parent test - There should be a parent problem
# encountered and it should quit the program
# without trying to display any data at all.
#
# NOTE: COMMENT OUT THE CHILD TEST ABOVE IF YOU
# WANT TO RUN THIS TEST.
# ----------------------------------------------
echo "" >&2
echo "Parent test - Problem in parent function but not in sub function." >&2
parentProblem=true
subProblem=false
returnedData=$( TestForParentProblem )
echo "Returned Data from parent function was: $returnedData" >&2
echo "----------------------------------------------------------------" >&2
echo "BUG MAIN 2: If you can read this, the program did not exit."      >&2
echo "----------------------------------------------------------------" >&2
_________________________
Tony Fabris