fread()、solaris 到 unix 的可移植性和未初始化值的使用

fread(), solaris to unix portability and use of uninitialised values

Valgrind 发现以下错误,我在阅读文档后,代码和这里的其他问题无法弄清楚原因。

Valgrind:第一次警告

~$ valgrind --vgdb=yes --vgdb-error=0 --read-var-info=yes --leak-check=yes --track-origins=yes debitadmin*

debitadmin  ==20720== Conditional jump or move depends on uninitialised value(s)
==20720==    at 0x4013BC6: initialise (dbg.c:199)
==20720==    by 0x4013F5C: ??? (in /opt/ivb/lib/libdbg.so)
==20720==    by 0x4013917: ??? (in /opt/ivb/lib/libdbg.so)
==20720==    by 0x5F5FFE: _dl_init (in /lib/ld-2.12.so)
==20720==    by 0x5E788E: ??? (in /lib/ld-2.12.so)
==20720==  Uninitialised value was created by a stack allocation
==20720==    at 0x4013A8F: initialise (dbg.c:150)

GDB 和 Valgrind:符号

(gdb) info symbol 0x4013A8F
initialise + 5 in section .text of /opt/ivb/lib/libdbg.so

(gdb) info symbol 0x4013BC6
initialise + 316 in section .text of /opt/ivb/lib/libdbg.so

代码:dbg.c

148    void
149    initialise(void)
150    {
151        register int i = 0;
152        char buffer[FILENAME_MAX] = "";
153        char *program = NULL;
154        struct sigaction act = {0};
...
... 
195         while ( ! feof(proc_file) && ! ferror(proc_file))
196         {
197             char ch;
198             fread(&ch,1,1,proc_file);
199             if ( ch != 0 )
200             fprintf(stderr,"%c",ch);
201             else
202             fprintf(stderr," ");
203         }

GDB:回溯

(gdb) bt
#0  0x04013bc6 in initialise () at dbg.c:199
#1  0x04013f5d in __do_global_ctors_aux () from /opt/ivb/lib/libdbg.so
#2  0x04013918 in _init () from /opt/ivb/lib/libdbg.so
#3  0x005f5fff in _dl_init_internal () from /lib/ld-linux.so.2
#4  0x005e788f in _dl_start_user () from /lib/ld-linux.so.2

GDB:本地人

(gdb) info locals
ch = 0 '[=14=]0'
c = 10

额外信息


我的理解:

Valgrind 抱怨

char ch; 

未初始化,即使在

之后
fread(&ch,1,1,proc_file);

在用 GDB ch 值检查上面一行后的值后,我有:

ch = 0 '[=17=]0'

proc_file 不对应,如您所见:

(gdb) print *proc_file
 = {
  _flags = -72538984, 
  _IO_read_ptr = 0x4352000 "debitadmin", 
  _IO_read_end = 0x4352000 "debitadmin", 
  _IO_read_base = 0x4352000 "debitadmin", 
  _IO_write_base = 0x4352000 "debitadmin", 
  _IO_write_ptr = 0x4352000 "debitadmin", 
  _IO_write_end = 0x4352000 "debitadmin", 
  _IO_buf_base = 0x4352000 "debitadmin", 
  _IO_buf_end = 0x4353000 <Address 0x4353000 out of bounds>, 
  _IO_save_base = 0x0, 
  _IO_backup_base = 0x0, 
  _IO_save_end = 0x0, 
  _markers = 0x0, 
  _chain = 0x79c580, 
  _fileno = 3, 
  _flags2 = 0, 
  _old_offset = 0, 
  _cur_column = 0, 
  _vtable_offset = 0 '[=18=]0', 
  _shortbuf = "", 
  _lock = 0x43dc0c0, 
  _offset = -1, 
  __pad1 = 0x0, 
  __pad2 = 0x43dc0cc, 
  __pad3 = 0x0, 
  __pad4 = 0x0, 
  __pad5 = 0, 
  _mode = -1, 
  _unused2 = '[=18=]0' <repeats 39 times>
}

没有 MCVE,因为我仍然不确定问题出在哪里,我指望专家帮助我解决这个问题。

所以,我的问题是,为什么在 fread() 赋值后 ch 还是空的?这是 Solaris 和 Linux 之间的可移植性问题吗?这是问题所在还是我遗漏了什么?

更新:文件已打开并检查是否为空。

#elif LINUX
    {
        char name[FILENAME_MAX];
    FILE *proc_file;
    sprintf(name,"/proc/%d/cmdline",(int)getpid());
    proc_file=fopen (name,"r");
    if ( proc_file != NULL )
    {
        int c;
        /* read in the programs name */
        for(c=0; ((fread(&buffer[c],1,1,proc_file)== 1) && (buffer[c]!=0)); c++);

        /* print out the program */
        (void)fprintf(stderr,"%s ", buffer);

        /* and the program arguments , not efficient but it works....*/
        fprintf(stderr," ");
        while ( ! feof(proc_file) && ! ferror(proc_file))
        {
            char ch;
            test *t;
            t = fread(&ch,1,1,proc_file);
            if ( ch != 0 )
            fprintf(stderr,"%c",ch);
            else
            fprintf(stderr," ");
        }
        (void) fprintf(stderr,"\n\n");
    }
    }
#endif

Q 1. why is ch empty even after fread() assignment?

(很可能)因为 fread() 失败了。请参阅下面的详细答案。

Q 2.Is this a portability issue between Solaris and Linux?

不,您的代码本身存在可能问题,valgrind 已正确报告。


我不能完全确定以下方法是否会解决您的问题,但您应该考虑以下几点来改进您的代码,例如,

  • 第 1 点: 检查 fread() to ensure sucess. If fread() is failure, using ch later will invoke read-before-write scenario. As ch is automatic local variable and not initialized explicitly, it will invoke undefined behaviour 的 return 值。

  • 第 2 点: 阅读:Why is while ( !feof (file) ) (almost) always wrong?