web-dev-qa-db-ja.com

free()はerrnoを設定しますか?

bufmalloc()で割り当てられた文字バッファーの場合、free(buf)errnoを設定/リセットしますか?

バッファが不要になったため、バッファをファイルに書き込んでから解放するとします。

コードのエラーポリシーがエラー時に-1を返すことであるとしましょう。

これは、メモリをリークすることなくバッファとエラーチェックを書き出す適切な方法ですか?

fputs(buf, somefile);
free(buf);
if (errno) return -1;

または、次のようにerrnoを自由に設定することを検討する必要がありますか...

fputs(buf, somefile);
if (errno){ 
    free(buf);
    return -1;
}
free(buf);

または、恐怖の恐怖、

do { 
  fputs(buf, somefile);
  int save_errno = errno;
  free(buf);
  errno = save_errno;
  if (errno) return -1;
} while(0);  

ブロックを使用すると、これを再利用する必要がある場合に、ローカルのsave_errnoをさまざまな場所に存在させることができます。

これはすべて、free()がerrnoを設定するかどうかに依存するようです。

free()のLinuxマニュアルページ は、malloc()などのマニュアルページでもあります。malloc()設定のerrnoについて言及していますが、free()については言及していません。

動的メモリを解放するためのGNU Cライブラリのマニュアルページ は、free()がerrnoを設定するかどうかについて言及していません。

そこで、free()がerrnoをリセットするかどうかを確認できるように、書き込みエラーを強制する短いプログラムを作成しましたが、そうではありません。この結果と、free()は非常に重要なので「もちろんerrnoを設定しない」という事実に頼るべきかどうか疑問に思っています。

# See if free() resets errno on a bad write
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
  char * buf = malloc(256);
  snprintf(buf,256,"%s\n", "Hello, World!");

  FILE *badfile;

  badfile = fopen("/dev/null","r");

  fputs(buf, badfile);
  free(buf);
  printf("%d\n", errno);
  printf("%s\n", strerror(errno));
}
61
Paul

POSIXは free を定義してerrnoを設定しません(POSIXは現在禁止していないため、実装で禁止されている場合があります- @を参照してくださいArjunShankarの答え 詳細)。しかし、それはあなたの懸念にはあまり関係がありません。

エラーをチェックする方法が正しくありません。 fputsの戻り値を確認し、0より小さいかどうかを確認してください。そうである場合は、errnoをチェックして、失敗の原因を突き止めることができますが、これはオプションです(さらに関数を呼び出す前に行う必要があります)。

だから、このようなものがうまくいくはずです:

int result = fputs(buf, somefile);
/* optionally read errno here if result < 0 (before the free call) */
free(buf);
return (result < 0) ? -1 : 0;
49

POSIX準拠のfreeerrnotodayを設定する可能性がありますが、将来的にはより良いものに変更される予定です。詳細:

  1. The Open Group Base Specifications Issue 7errno の定義は次のように述べています。

このボリュームのPOSIX.1-2008の関数は、errnoを0に設定しません。関数の呼び出しが成功した後のerrnoの設定は、その関数の説明でerrnoを変更しないことを指定していない限り、指定されていません。

  1. free の定義自体は、freeerrnoで何をするかを指定していません。

これは、準拠しているfree実装がerrnoを0にリセットしないことを意味します。ただし、ゼロ以外の値に設定する場合としない場合があります。

ただし、仕様の第8号(進行中の作業)は freeが設定されないことを具体的に保証するためにerrnoが必要です =有効な入力が渡​​されたとき

glibc は、この新しい要件に準拠するためにすでに準備を進めています。

34
ArjunShankar

C標準のerrnoの説明では、freeについて何も言われていません。したがって、この機能に依存することはできません。

C標準によると(7.5エラー<errno.h>

3 ...この国際規格の関数の説明にerrnoの使用が記載されていない限り、エラーの有無にかかわらず、ライブラリ関数呼び出しによってerrnoの値がゼロ以外に設定されることがあります。

また、errnoの使用については、すでに述べたように、C標準のfreeの説明には記載されていません。

16

参照が失敗時に関数がerrnoでエラーコードを返すと言っていない場合、それはしません。

errnoをエラーコードに設定する関数は、(ほとんどの場合)errnoに現在のエラーコードが含まれることを別の方法で通知します。メモリ割り当て関数はNULLを返し、他の多くの関数はゼロまたは負の数など。
このような関数は、成功した場合でもerrnoを変更する必要はなく、通常は変更されません。

通常、errnoを検査して、問題が発生したかどうかを判断することはできません。エラーが発生したことがわかった場合にのみ、より多くの情報を取得するためのものです。

最終規則の1つの例外はstrto{l, d, ul}ファミリですが、最初の段落はそれらにも当てはまります。
また、失敗した場合を除いて、必ずしもerrnoを設定する必要はないため、最初にクリアする必要があります。そうしないと、古いエラーコードが含まれる可能性があります。

13
molbdnilo