s117 / anycore-riscv

The AnyCore toolset targetting the RISC-V ISA
Other
0 stars 0 forks source link

fopen(filename, "w") has unexpected behavior in GCC 9.2.0 newlib toolchain #7

Closed s117 closed 4 years ago

s117 commented 4 years ago

We expect that the libc call fopen("XYZ", "w") creates an empty file named "XYZ" for output operations. But with 9.2.0 newlib toolchain aforementioned call returns NULL.

This weird behavior is observed when running SPEC2006 456.hmmer_ref.

A C code piece to reproduce this problem:

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <fcntl.h>

void Die(char *format, ...) {
  va_list argp;
  /* format the error mesg */
  fprintf(stderr, "\nFATAL: ");
  va_start(argp, format);
  vfprintf(stderr, format, argp);
  va_end(argp);
  fprintf(stderr, "\n");
  fflush(stderr);
  /* exit  */
  exit(1);
}

int main() {
  const char *tmpfile = "./bombesin.hmm.new";
  const char *mode = "w";
  FILE *outfp;
  printf("O_CREAT=0x%08x\n", O_CREAT);

  if ((outfp = fopen(tmpfile, mode)) == NULL)
    Die("Ouch. Temporary file %s couldn't be opened for writing.", tmpfile);

  fputs("TEMPDATA\n", outfp);
  fclose(outfp);

  printf("Temporary file %s was opened correctly.\n", tmpfile);
  return 0;
}

Result:

➜  fwrite_test ls
fwrite.c
➜  fwrite_test riscv64-unknown-elf-gcc -g fwrite.c -o fwrite
➜  fwrite_test ls
fwrite  fwrite.c
➜  fwrite_test spike pk fwrite
Requesting target memory 0x100000000
******* Resetting core ********** 
****Initializing the processor system****
******* Resetting core ********** 
******* Resetting core ********** 
****Initialization complete****
O_CREAT=0x00000200

FATAL: Ouch. Temporary file ./bombesin.hmm.new couldn't be opened for writing.
******* Resetting core ********** 
➜  fwrite_test ls
fwrite  fwrite.c
s117 commented 4 years ago

In short, it happens because of an OS API difference. It has been thoroughly discussed in these two related issues: https://github.com/riscv/riscv-gnu-toolchain/issues/510 https://github.com/riscv/riscv-tools/issues/229

One workaround is to use the Linux encoding overriding the newlib's FreeBSD-style encoding, as provided by https://github.com/s117/riscv-newlib/commit/90283440c35651d12622fd2e4135308ed107cec8

Though seems dirty, it does work.

➜  fwrite_test ls                                           
fwrite.c
➜  fwrite_test riscv64-unknown-elf-gcc -g fwrite.c -o fwrite
➜  fwrite_test ls
fwrite  fwrite.c
➜  fwrite_test spike pk fwrite
Requesting target memory 0x100000000
******* Resetting core ********** 
****Initializing the processor system****
******* Resetting core ********** 
******* Resetting core ********** 
****Initialization complete****
O_CREAT=0x00000040
Temporary file ./bombesin.hmm.new was opened correctly.
******* Resetting core ********** 
➜  fwrite_test ls
bombesin.hmm.new  fwrite  fwrite.c
➜  fwrite_test cat bombesin.hmm.new 
TEMPDATA
s117 commented 4 years ago

58d5ac3 updated submodule riscv-gnu-toolchian to incorporate this patch