简体   繁体   中英

What could cause return values to differ between HP-UX and LINUX for C++ application?

In the process of porting an HP-UX C++ application over to LINUX, I've noticed that there was a function of type int where not all code paths appear to return an integer value. When I compile and run the application under HP-UX (using the acc compiler for compilation), it returns a 0 through a codepath that does not explicitly state a return value. However, when I compile and run the same application under LINUX, I get a return value of -72 and the application presents an error consequently (this is intended when the return value is less than 0). I've noticed that classic C++ (a very old and outdated standard which the ACC compiler supports) deals with variable scoping a bit differently from standard C++ (which ACC unfortunately does not support). In classic C++, it appears that declaring an integer inside a forloop declaration

for( int index = 0; index < array.length; index++ )

the variable index is accessible outside the forloop, although I wouldn't know for sure whether the return statements are dealt with in the same way such that aCC recognizes that all code paths return a value.

The function i'm dealing with is available below:

int process_phase (const char *phase, const char *seg_type, const char *dist_target, const char *action_target, char *cmd) 
{
  char cmd2[MAX_STRING];

  printf( "I AM INSIDE THE PROCESS_PHASE\n" );

  if (TRACE_MODE) 
  {
    printf ("%s %s\n", MSG_LOOKUP("MSG_PHASE"), phase);
    printf ("%s %s\n", MSG_LOOKUP("MSG_SEG_TYPE"), seg_type);
    printf ("%s %s\n", MSG_LOOKUP("MSG_DIST_TARGET"), dist_target);
    printf ("%s %s\n", MSG_LOOKUP("MSG_ACTION_TARGET"), action_target);
    printf ("%s %s\n", MSG_LOOKUP("MSG_CMD"), cmd);
  }

  // Remove the pre- and post- prefixes
  const char *phase_ref = strchr(phase, '-');

  printf ("PHASE REF BEFORE PREFIX REMOVAL: %s\n", phase_ref );

  if (phase_ref) 
  {
    phase_ref++; 
  }
  else
  {
    phase_ref = phase;
  }

  printf ("PHASE REF AFTER PREFIX REMOVAL: %s\n", phase_ref );

  if (TRACE_MODE)
  {
    printf ("%s %s\n", MSG_LOOKUP("MSG_PHASE_REF"), phase_ref);
  }

  printf ( "==========TEST PHASE 1 BEGIN==========\n" );

  if (strcasecmp(phase_ref, "all_phases") != 0) 
  {
    if (DO_TRANSFER && strcasecmp(phase_ref, "transfer") != 0) 
    {
      printf ("IN ONE\n");
      return 0;
    }
    else if (DO_TAPE_GENERATION && strcasecmp(phase_ref, "tape_generation") != 0) 
    {
      printf ("IN TWO\n");
      return 0;
    }
    else if (DO_TAPE_EXTRACTION && strcasecmp(phase_ref, "tape_extraction") != 0) 
    {
      printf ("IN THREE\n");
      return 0;
    }
    else if (DO_PREPARATION && strcasecmp(phase_ref, "preparation") != 0)
    {
      printf ("IN FOUR\n");
      return 0;
    }
    else if (DO_DISTRIBUTION && strcasecmp(phase_ref, "distribution") != 0)
    {
      printf ("IN FIVE\n");
      return 0;
    }
    else if (DO_VERIFICATION && strcasecmp(phase_ref, "verification") != 0)
    { 
      printf ("IN SIX\n");
      return 0;
    }
    else if (DO_ACTIVATION && strcasecmp(phase_ref, "activation") != 0) 
    {
      printf ("IN SEVEN\n");
      return 0;
    }
    else if (DO_REMOVAL && strcasecmp(phase_ref, "removal") != 0)
    {
      printf ("IN EIGHT\n");
      return 0;
    }
  }

  printf ( "==========TEST PHASE 1 END==========\n" );

  // if (strstr(seg_type, envvar("SEGMENT_TYPE")) == 0 && strcasecmp(seg_type, "ALL") !=0) return 0;
  char tmp_seg_type[MAX_BUFFLEN];
  sprintf (tmp_seg_type, "_%s_", seg_type);

  printf( "tmp_seg_type: %s\n", tmp_seg_type );

  char tmp_envar_seg_type[MAX_BUFFLEN];
  sprintf (tmp_envar_seg_type, "_%s_", envvar("SEGMENT_TYPE"));

  printf( "tmp_seg_type: %s\n", tmp_seg_type );

  if ( strstr(tmp_seg_type, tmp_envar_seg_type) == 0 && strcasecmp(seg_type, "ALL") != 0 )
  {
    printf( "IN TEST PHASE TWO\n" );
    return 0;
  }

  char match_list[MAX_BUFFLEN];

  printf ( "==========TEST PHASE THREE BEGIN==========\n" );

  if ( DO_TRANSFER ) 
  {
    printf( "IN ONE\n" );
    sprintf( match_list, "DIST_NODES", dist_target );
  }
  else if (DO_TAPE_GENERATION) 
  {
    printf( "IN TWO\n" );
    sprintf( match_list, "HOST_NODES", dist_target );
  }
  else
  {
    printf( "IN THREE\n" );
    sprintf( match_list, "%s_NODES", dist_target );
    printf( "match_list: %s\n", match_list );
  }

  printf ( "==========TEST PHASE THREE END==========\n" );

  char matched_nodes[MAX_BUFFLEN];
  get_env(match_list, matched_nodes);

  printf( "matched_nodes: %s\n", matched_nodes );

  word_sort_unique(matched_nodes);

  printf( "sorted_matched_nodes: %s\n", matched_nodes );

  const char *element_separator = " ";
  const char *curr_node_type;
  char *curr_node = strtok(matched_nodes, element_separator);

  printf( "curr_node: %s\n", curr_node );

  int whileiteration = 0;

 while (curr_node) 
 {
    printf( "WHILE LOOP ITERATION: %d\n", whileiteration );

    int node_idx;
    bool matched = false;

    for (node_idx=0; node_idx<node_count; node_idx++) 
    {
      if (strcmp(curr_node, node_table[node_idx]) == 0) 
      {
        matched = true;
        break;
      }
    }

    if (matched) 
    {
      if (strcasecmp(action_target, "TARGET") == 0) 
      {
        if (indent[node_idx][0] == 0) 
        {
          fprintf (outfile[node_idx], "remsh %s \"\n", curr_node);
          indent[node_idx] = "  ";
          fprintf (outfile[node_idx], "%s. %s/site_profile\n", indent[node_idx], envvar ("TOOLS_DIR"));
          fprintf (outfile[node_idx], "%s. %s/install_profile\n", indent[node_idx], envvar ("TOOLS_DIR"));
          fprintf (outfile[node_idx], "%sexport LANG=%s\n", indent[node_idx], envvar ("LANG"));
        }
      } 
      else 
      {
        // Input redirection from /dev/echo enables that the ports reserved for remsh on both client and
        // server node get released immediately without any inactivity timeout period
        if (indent[node_idx][0] != 0) 
        {
          fprintf (outfile[node_idx], "\" < /dev/echo \n");
        }
        indent[node_idx] = "";
      }

      // Do parameter substitution
      strcpy(cmd2, cmd);
      expand_string (cmd2, "$BUILD_VERSION", BUILD_VERSION);
      expand_string (cmd2, "${BUILD_VERSION}", BUILD_VERSION);
      expand_string (cmd2, "$TARGET_NODE", curr_node);
      expand_string (cmd2, "${TARGET_NODE}", curr_node);
      curr_node_type = target_lookup (curr_node);      
      expand_string (cmd2, "$NODE_TYPE", curr_node_type);
      expand_string (cmd2, "${NODE_TYPE}", curr_node_type);

      fprintf(outfile[node_idx], "%s%s\n", indent[node_idx], cmd2);
      file_active[node_idx] = true;
    }
    curr_node = strtok(NULL, element_separator);

    whileiteration++;
  }
  printf ( "EXITING PROCESS PHASE\n" );
}

I've use code instrumentation to print out variables and other output on HP-UX and LINUX up until the while loop and they appear to be the same. Under certain circumstances, even when the while loop is ignored because the variable curr_node is null and the function is exited, where EXITING PROCESS PHASE is printed to stdout, the output is the same between HP-UX and LINUX. However, the return values between HP-UX and LINUX is completely different. What I can't figure out is why.

You say there's a branch of your function "that does not explicitly state a return value." That's an error that the compiler is not required to diagnose for you. Behavior is undefined in that situation. That you've consistently gotten a negative result on one platform just means you're lucky (or unlucky, since different values wouldn't have exposed this error sooner otherwise).

Usually, there's a memory location or register designated for the return value to go. If the function doesn't store anything there, or if it's used the location for a temporary value but never written a final result there, then the caller will read that location and get whatever value happened to be there. The location for Linux return values happens to hold -72 in your case, whereas the location for HP-UX return values happens to hold zero. Make your intentions known and return a value explicitly in all code paths.

Whether the return-value locations consistently hold a particular value will often be affected by the actions of the function in question, as well as the actions of the functions it calls. Behavior of small, simple functions won't necessarily predict the behavior of larger functions.

int values are most often returned in a register. If you don't actually return a value, that register will contain some random value remaining from previous computations.

If you reach the end of this function, you will have a return value from the last printf that will likely be passed on to the next level.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM