int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
...open()...O_CREAT 标志...
如果没有指定 mode 怎么办?
除了其他人的答案之外,如果您想通过 getting a 编译器错误 当你忘记在需要它的情况下指定 mode 标志时(即 O_CREAT 或 O_TMPFILE,根据@987654326 @),您必须使用 GNU 项目C 和C++ 编译器(例如gcc 命令)和arg。 -D_FORTIFY_SOURCE=1(或2)和一个优化标志,例如。 -O1 或通常的 -O2(因为 _FORTIFY_SOURCE requires compiling with optimization (-O))。
例如:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int file;
static const char filename[] = "test.test";
if ((file = open(filename, O_RDWR | O_CREAT | O_TRUNC)) == 1)
{
perror("Error opening file.");
exit(EXIT_FAILURE);
}
close(file);
}
(另存为文件:a.c)
$ gcc -D_FORTIFY_SOURCE=2 -O1 a.c
In file included from /usr/include/fcntl.h:328,
from a.c:3:
In function ‘open’,
inlined from ‘main’ at a.c:10:13:
/usr/include/bits/fcntl2.h:50:4: error: call to ‘__open_missing_mode’ declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments
__open_missing_mode ();
^~~~~~~~~~~~~~~~~~~~~~
所以你得到:open with O_CREAT or O_TMPFILE in second argument needs 3 arguments
学究跟随:
请注意:-O0 或没有 -O arg。不起作用(即它不会告诉您忘记添加mode,因为好像_FORTIFY_SOURCE 未指定或被忽略):
$ gcc -D_FORTIFY_SOURCE=2 -O0 a.c
In file included from /usr/include/bits/libc-header-start.h:33,
from /usr/include/stdio.h:27,
from a.c:1:
/usr/include/features.h:382:4: warning: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Wcpp]
# warning _FORTIFY_SOURCE requires compiling with optimization (-O)
^~~~~~~
使用_FORTIFY_SOURCE 也会像other cases 一样保护您,而对于open(),还有另一种情况:open can be called either with 2 or 3 arguments, not more,在文件/usr/include/bits/fcntl2.h 中可以看到:
__errordecl (__open_too_many_args,
"open can be called either with 2 or 3 arguments, not more");
__errordecl (__open_missing_mode,
"open with O_CREAT or O_TMPFILE in second argument needs 3 arguments");
__fortify_function int
open (const char *__path, int __oflag, ...)
{
if (__va_arg_pack_len () > 1)
__open_too_many_args ();
if (__builtin_constant_p (__oflag))
{
if (__OPEN_NEEDS_MODE (__oflag) && __va_arg_pack_len () < 1)
{
__open_missing_mode ();
return __open_2 (__path, __oflag);
}
return __open_alias (__path, __oflag, __va_arg_pack ());
}
if (__va_arg_pack_len () < 1)
return __open_2 (__path, __oflag);
return __open_alias (__path, __oflag, __va_arg_pack ());
}
需要 GNU C 编译器(例如 gcc)的原因至少是因为文件 /usr/include/sys/cdefs.h 中的以下代码:
#if __GNUC_PREREQ (4,3)
# define __warndecl(name, msg) \
extern void name (void) __attribute__((__warning__ (msg)))
# define __warnattr(msg) __attribute__((__warning__ (msg)))
# define __errordecl(name, msg) \
extern void name (void) __attribute__((__error__ (msg)))
#else
# define __warndecl(name, msg) extern void name (void)
# define __warnattr(msg)
# define __errordecl(name, msg) extern void name (void)
#endif
这表示 gcc 版本 4.3 是此工作所需的最低版本。
(仅供参考:我当前的版本是 gcc (GCC) 8.3.0)
所以如果你尝试clang version 8.0.0 (tags/RELEASE_800/final) Target: x86_64-pc-linux-gnu,你不会得到编译错误:
$ clang -D_FORTIFY_SOURCE=2 -O1 a.c
(即使带有 - 也没有输出,编译成功:a.out 创建)
因为这个 clang 版本将 __GNUC__ 定义为 4 和 __GNUC_MINOR__ 为 2 因此 4.2 只比它工作所需的 4.3 略差;并强迫例如。 8.3 不起作用:
$ clang -D_FORTIFY_SOURCE=1 -D__GNUC__=8 -D__GNUC_MINOR__=8 -O1 a.c
In file included from <built-in>:355:
<command line>:2:9: warning: '__GNUC__' macro redefined [-Wmacro-redefined]
#define __GNUC__ 8
^
<built-in>:9:9: note: previous definition is here
#define __GNUC__ 4
^
In file included from <built-in>:355:
<command line>:3:9: warning: '__GNUC_MINOR__' macro redefined [-Wmacro-redefined]
#define __GNUC_MINOR__ 8
^
<built-in>:7:9: note: previous definition is here
#define __GNUC_MINOR__ 2
^
2 warnings generated.
以上源码来自 Arch Linux 上的glibc 2.29.9000.r269.g1f50f2ad85-1 包。即。
/usr/include/sys/cdefs.h is owned by glibc 2.29.9000.r269.g1f50f2ad85-1
/usr/include/bits/fcntl2.h is owned by glibc 2.29.9000.r269.g1f50f2ad85-1
PS:没有_FORTIFY_SOURCE,你可以在每个程序运行时获得随机模式,比如I did:
$ ./go
-r-x--s--T 1 user user 0 May 17 17:22 /tmp/broken_perms.log
$ ./go
---sr-s--- 1 user user 0 May 17 17:23 /tmp/broken_perms.log
$ ./go
-rws--x--- 1 user user 0 May 17 17:23 /tmp/broken_perms.log
$ ./go
--wsr-x--T 1 user user 0 May 17 17:23 /tmp/broken_perms.log