Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fopen + fgets does not work #547

Closed
realmonster opened this issue Aug 10, 2023 · 2 comments
Closed

fopen + fgets does not work #547

realmonster opened this issue Aug 10, 2023 · 2 comments

Comments

@realmonster
Copy link

Sample program.

#include <stdio.h>

int main()
{
    FILE *f = fopen("mysave.txt","w");
    fprintf(f, "my info");
    fclose(f);
    f = fopen("mysave.txt", "r");
    char buff[1000];
    char *res = fgets(buff, sizeof(buff) - 1, f);
    fclose(f);
    printf("%p\n%s\n", res, buff);
    return 0;
}

Testing:

$ gcc testfgets.c -o testfgets
$ ./testfgets
0x7ffd5aaa6270
my info
$ libTAS ./testfgets
Attempt 1: Connected.
[libTAS f:0] Thread 22322 (main) fopen call with filename mysave.txt and mode w
[libTAS f:0] Thread 22322 (main)   savefile detected
[libTAS f:0] Thread 22322 (main) fclose call.
[libTAS f:0] Thread 22322 (main) fopen call with filename mysave.txt and mode r
[libTAS f:0] Thread 22322 (main)   savefile detected
[libTAS f:0] Thread 22322 (main) fclose call.
(nil)
��u(
[libTAS f:0] Thread 22322 (main) close call
[libTAS f:0] Thread 22322 (main) Unknown file descriptor 4

Expected result: to see non null pointer, and "my info" text.

@CasualPokePlayer
Copy link
Contributor

Seems that fgets works perfectly fine. The issue is that the first call to fopen for the "save file" using "w". This marks the "file" as write-only. The later fopen ends up not re-opening the file (due to the logic of save files), resulting in fgets rejecting the file as it sees it as write-only. If the first fopen call is changed to open the file as "w+" it ends up working out.

@realmonster
Copy link
Author

thanks to @CasualPokePlayer for the info which helped me to find out one of possible solutions.

to reproduce bug without libTAS, here is a code:

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int fd = memfd_create("mysave.txt", 0);
    FILE *f = fdopen(fd, "w");
    fwrite("my info", 1, 7, f);
    fseek(f, 0, SEEK_SET);
    char buff[1000];
    memset(buff, 0, sizeof(buff));
    printf("%p\n", f);
    char *res = fgets(buff, sizeof(buff) - 1, f);
    printf("fclose %d\n", fclose(f));
    printf("%p\n%s\n", res, buff);
    return 0;
}

Because libTAS doesn't close files, this still "w", and glibc doesn't allow fgets for "w" files. If we set "w+" we will be able to read it. and it will print actual data.

But we want to have new FILE* with appropriate mode. This is possible using dup. Here is an example:

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int fd = memfd_create("mysave.txt", 0);
    int fdcopy = dup(fd);
    FILE *f = fdopen(fd, "w");
    printf("f=%p\n", f);
    fwrite("my znfz", 1, 7, f);
    fseek(f, 0, SEEK_SET);
    char buff[1000];
    memset(buff, 0, sizeof(buff));
    printf("read=%d\n", fread(buff, 1, 1, f));
    fclose(f);
    FILE *f1 = fdopen(fdcopy, "r");
    printf("f1=%p", f1);
    char *res = fgets(buff, sizeof(buff) - 1, f1);
    printf("%p\n%s\n", res, buff);
    printf("write=%d\n", fwrite(buff, 1, 1, f1)); 
    printf("fclose %d\n", fclose(f1));
    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants