0

I'm trying to use a clean method to pass all user input to different parts of the program.

However, there's a bug. My problem is that the string holding one of the user's arguments gets converted into garbage values for seemingly no reason.

Before an unrelated function call inside the send function, the string is perfect, afterwards, it is filled with garbage values.

Provided are the cleaned-up snippets from a larger project that has this issue. Only the code that is relevant to this issue is shown.

This is occurring on ubuntu.

// weirdInputBug.c

#include <stdio.h>
#include <ctype.h>

typedef struct UserInput {
    char command;  // The character that represents the command to be executed
    int argument1;
    int intArgument2;
    char *strArgument2;
} UserInput;

// This is to force the compiler to use all 3 variables in registers
int functionThatUsesManyParameters(int a, int b, int c) {
    return a;
}

void send(int pid, char *msg) {
    printf("msg in send before function call: %s\n", msg);  fflush(stdout);

    // Force the compiler/program to use first 3 variable registers
    int a, b, c;
    functionThatUsesManyParameters(a, b, c);

    printf("msg in send after function call: %s\n", msg);  fflush(stdout);
    return;
}

// Return the user's command
UserInput getUserInput() {
    // Initialize variables and get user input
    char msg[40];
    printf("Please type \"s 1 hi\": ");
    fflush(stdin);
    scanf("%s", msg);
    msg[0] = toupper(msg[0]);

    // Initialize structure variables
    char command;
    int argument1 = -1;
    int intArgument2 = -1;
    char strArgument2[40] = "";

    // Assign structure variables
    command = msg[0];
    scanf("%d", &argument1);
    scanf("%39s", strArgument2);

    // Return completed structure
    return (UserInput){command, argument1, intArgument2, strArgument2};
}

int main() {
    // Get the user's input
    UserInput userInput = getUserInput();

    // Choose what the program does based on the command
    switch (userInput.command) {
        case 'S':
            printf("msg in main: %s\n", userInput.strArgument2);  fflush(stdout);
            send(userInput.argument1, userInput.strArgument2);
            break;
        default:
            break;
    }
}

Makefile:

run: weirdInputBug.c
    gcc -o run weirdInputBug.c -I.

Process output:

sephorol@ubuntu:~/Downloads/help$ ./run
Please type "s 1 hi": s 1 hi
msg in main: hi
msg in send before function call: hi
msg in send after function call: 0����
  • You're returning a pointer to a local variable from `getUserInput()` in `strArgument2` so it gets scrambled because it is no longer valid. The primary culprit is probably `printf()`; repeating the call to it at the top of `send()` would confirm that. – Jonathan Leffler Mar 19 '20 at 02:36
  • 1
    `getUserInput` returns a `UserInput` structure that has a pointer to a variable local to the `getUserInput` function (`strArgument2`). Undefined behavior. As a bonus, you also do `fflush(stdin)`, which is also undefined behavior. – jamesdlin Mar 19 '20 at 02:36
  • Be wary of [Using `fflush(stdin)`](https://stackoverflow.com/q/2979209/115168). – Jonathan Leffler Mar 19 '20 at 02:37

1 Answers1

1

char strArgument2[40]; this is a local variable, stored on the stack. The function getUserInput() returns a struct pointing that local variable with it's scope left. When printf is called first time, it's just a lucky moment. When printf is called second time, the stack contains garbage data and the struct points to that garbage string value.

273K
  • 29,503
  • 10
  • 41
  • 64