Bogus'可能未经初始化使用

时间:2018-04-25 08:28:42

标签: c

我在下面的代码中收到了一个单一化的警告,我很难理解为什么。 我看不到未经初始化使用的代码路径。任何人都可以帮忙吗? 另外,我可以使用一些adivce,如果我的gotos使用不好或者有更干净的方法这样做。

 In function ‘handle_comp_enc’:
fs/compress.c:101:8: warning: ‘write_cdata’ may be used uninitialized in this function [-Wmaybe-uninitialized]
   kfree(write_cdata);

代码:

#define ENC  (1UL << 1)
#define ZIP  (1UL << 2)
#define ENC_ZIP_ENABLED(cmp_enc_flags) ((cmp_enc_flags) & (ENC | ZIP)) == (ENC | ZIP)


int handle_comp_enc(unsigned long comp_enc_flags, unsigned char *read_data,
                        size_t read_len, unsigned char *write_data, size_t *write_len2) {
        unsigned char *write_cdata, *rd_enc_data;
        size_t write_clen, enc_src_len;
        int err;
        if (ENC_ZIP_ENABLED(comp_enc_flags)){
                write_cdata = kmalloc(get_compress_fsize(PAGE_SIZE), GFP_KERNEL);
                if (!write_cdata) {
                        err  = -ENOMEM;
                        goto zip_only;
                }
        }
        else if(!(comp_enc_flags & ENC))
                write_cdata = write_data;
        else{
                rd_enc_data = read_data;
                enc_src_len = read_len;
                goto enc_only;
        }
        err = do_compress(read_data, read_len, write_cdata, &write_clen);
        if (err < 0) {
                goto out_enc_zip;
        }
        if (!(comp_enc_flags & ENC)) {
                *write_len2 = write_clen;
                goto zip_only;
        }
        rd_enc_data = write_cdata;
        enc_src_len = write_clen;
enc_only:
        err = do_skcipher_encrypt(rd_enc_data, enc_src_len, write_data, write_len2);
        if (err < 0) {
        }
out_enc_zip:
        if (ENC_ZIP_ENABLED(comp_enc_flags))
                kfree(write_cdata);
zip_only:
        return err;
}

2 个答案:

答案 0 :(得分:3)

编译器最好发出警告,因为消息说&#34;也许&#34;,编译器不知道标签{ENC_ZIP_ENABLED(comp_enc_flags)将是假的out_enc_zip 1}}。您的代码未使用未初始化的值。

那就是说,我强烈不同意你的goto用例,你的代码是不可读的,我花了很多时间来了解代码的去向。

您的代码可能会被简化很多,我不确定此代码是否与我所说的代码难以阅读的行为相同:

#define ENC  (1UL << 1)
#define ZIP  (1UL << 2)

int handle_comp_enc(unsigned long comp_enc_flags, unsigned char *read_data,
                    size_t read_len, unsigned char *write_data, size_t *write_len2) {
        if ((comp_enc_flags & (ENC | ZIP)) == (ENC | ZIP)) {
            unsigned char *tmp = kmalloc(get_compress_fsize(PAGE_SIZE), GFP_KERNEL);
            if (!tmp) {
                    return -ENOMEM;
            }
            size_t size;
            int err = do_compress(read_data, read_len, tmp, &size);
            if (!(err < 0)) {
                err = do_skcipher_encrypt(tmp, size, write_data, write_len2);
            }
            kfree(tmp);
            return err;
        }
        else if (!(comp_enc_flags & ENC)) {
              return do_compress(read_data, read_len, write_data, write_len2);
        }
        else {
            return do_skcipher_encrypt(read_data, read_len, write_data, write_len2);
        }
}

答案 1 :(得分:1)

是的,这看起来像是误报。在if-else if-else中,您只在ifelse if语句中初始化变量。显然你得到的工具与goto或其他一些混淆。

但这并不重要,因为问题的根源是功能设计。您没有默认初始化变量,并且您在内存分配和实际算法之间存在紧密耦合。在这里使用goto是可以的,但它会稍微降低可读性。

我会将它拆分为两个函数,将内存处理和错误处理留给外部函数。这段伪代码的某些内容会更具可读性:

int wrapper_function ( ... )
{
  unsigned char *write_cdata = NULL;
  int err = initialize_me_to_something.

  if(ENC_ZIP_ENABLED(comp_enc_flags))
  {
    write_cdata = kmalloc (...
    if(write_cdata == NULL)
    {
      return -ENOMEM;
    }
  }
  else
  {
    if(!(comp_enc_flags & ENC)
    {
      write_cdata = write_data;
      ...
    }
    else
    { // some special case
      err = do_skcipher_encrypt(...
      return err;
    }
  }


  err = do_the_actual_job(write_cdata, otherparameters); 

  if (err < 0) 
  {
    cleanup();
  }

  return err;
}

goto不一定是邪恶的,但也不是多个返回语句。他们对所提供的或多或少理性的论点都不满意。但是,多个return语句往往比“on error goto”模式提高了可读性。最重要的是,他们倾向于自然地提供更好的程序设计,具有多个小功能而不是单个大功能。

作为副作用,您可以省去一些额外的分支指令,这可能会略微提升性能。