简体   繁体   中英

Memory leaks with kbhit for Linux

The code is here . When I run my program (I saved kbhit as a header file and kept it in my program folder), I get an uninitialized read access on the first instance of using kbhit (I am using DrMemory for memory debugging). I included sys/ioctl.h as my program wasn't able to use FIONREAD without it. The thing that is having an issue is the call to tcsetattr(STDIN, TCSANOW, &term); I don't fully understand how this works so any help would be appreciated. Thank you!

Edit: the exact message is “UNINITIALIZED READ: reading 12 bytes. system call ioctl.0x5402 parameter #2.” The line is from the tcsetattr() call. This error comes after saving kbhit as a cpp file and templating it in another file. The program runs just fine except for that one error.

Here is a version of the code which I modified to be actual C and not C++, since it was only being C++ out of carelessness with bool true/false and struct keywords.

And oh yeah, don't put this in a header file. Put it in a file called kbhit.c and delete or comment out the test main function. And in a header file just write the line:

int _kbhit(void);

Or you might need:

extern "C" int _kbhit(void);

That's all you need in the header.

/**
 Linux (POSIX) implementation of _kbhit().
 Morgan McGuire, morgan@cs.brown.edu
 */
#include <stdbool.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>

int _kbhit(void) {
        static bool initialized = false;

        if (! initialized) {
                // Use termios to turn off line buffering
                struct termios term;
                tcgetattr(STDIN_FILENO, &term);
                term.c_lflag &= ~ICANON;
                tcsetattr(STDIN_FILENO, TCSANOW, &term);
                setbuf(stdin, NULL);
                initialized = true;
        }

        int bytesWaiting;
        ioctl(STDIN_FILENO, FIONREAD, &bytesWaiting);
        return bytesWaiting;
}

//////////////////////////////////////////////
//      Simple demo of _kbhit()

int main() {
        printf("Press any key");
        while (! _kbhit()) {
                printf(".");
                fflush(stdout);
                usleep(1000);
        }
        printf("\nDone.\n");

        return 0;
}

It looks correct to me and valgrind does not complain. I don't have Dr. Memory to check with.

How this code works is that it first uses tcgetattr to read the termios (terminal input output settings, I think) struct. Then it modifies it by unsetting the ICANON bits. Canon is the canonical setting for terminals which includes line buffering. Then it writes the new termios values back to the terminal. with tcsetattr .

The ioctl call gets how many bytes are waiting in the buffer. If there's bytes waiting, then someone pressed some kind of keys.

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