- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在编写一个小程序来测试 exec 系统调用中的 E2BIG 错误情况。如果传递的参数超过 limits.h 中指定的 MAX_ARG,则会出现 E2BIG 错误。在某些情况下,如果超过最大参数大小,RLIMIT_STACK 也会报错。
pid = fork();
if(0 == pid){ /*CHILD*/
printf("\n Child : %d \n",getpid());
getrlimit(RLIMIT_STACK,&limit);
printf("\n cur limit : %d , max limit : %d \n",(unsigned int)limit.rlim_cur,(unsigned int)limit.rlim_max);
limit.rlim_cur = 0;
limit.rlim_max = 0;
setrlimit(RLIMIT_STACK,&limit);
printf("\n cur limit : %d , max limit : %d \n",(unsigned int)limit.rlim_cur,(unsigned int)limit.rlim_max);
execl("/usr/bin/ls","ls",NULL);
printf("\n Child is done! \n");
}
else if(pid > 0){ /*PARENT*/
waitpid(pid,&status,0);
printf("\n Parent : %d \n",getpid());
printf("\n Child : %d exited with exit_status %d \n",pid,status);
}
else{ /*ERROR*/
switch(errno){
case E2BIG:
perror("\n E2BIG");
break;
}
}
最佳答案
此代码有点粗略地探测限制,每次测试参数列表大小时都会将参数列表的大小加倍。如果您愿意,您可以对其进行优化(因此它会在上次成功和第一次失败之间的范围内搜索),但它有可能在第一次就正确地达到极限。
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
enum { BYTES_PER_KIBIBYTE = 1024 };
enum { BYTES_PER_MEBIBYTE = BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE };
enum { E_GOT_E2BIG = 37 };
enum { E_NOT_E2BIG = 219 };
static void sigchld_handler(int signum)
{
signal(signum, sigchld_handler);
}
int main(void)
{
signal(SIGCHLD, sigchld_handler);
for (int i = 4 * BYTES_PER_KIBIBYTE; i < BYTES_PER_MEBIBYTE; i *= 2)
{
fflush(0);
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "Failed to fork at %d\n", i);
return 1;
}
else if (pid == 0)
{
int self = getpid();
printf("Child: %d\n", self);
char *args[10] = { "ls" };
size_t bytes_per_arg = i / 8;
for (int j = 1; j < 9; j++)
{
args[j] = malloc(bytes_per_arg + 1);
if (args[j] == 0)
{
fprintf(stderr, "Failed to allocate argument space at size %d\n", i);
exit(E_NOT_E2BIG);
}
memset(args[j], j + '0', bytes_per_arg);
args[j][bytes_per_arg] = '\0';
}
/* Close standard I/O channels so executed command doesn't spew forth */
int dev_null = open("/dev/null", O_RDWR);
if (dev_null < 0)
{
fprintf(stderr, "Failed to open /dev/null for reading and writing\n");
exit(E_NOT_E2BIG);
}
int dev_stderr = dup(2);
if (dev_stderr < 0)
{
fprintf(stderr, "Failed to dup() standard error\n");
exit(E_NOT_E2BIG);
}
close(0);
dup(dev_null);
close(1);
dup(dev_null);
close(2);
dup(dev_null);
close(dev_null);
/* Execute ls on big file names -- error is ENAMETOOLONG */
execvp(args[0], args);
/* Reinstate standard error so we can report failure */
dup2(dev_stderr, 2);
int errnum = errno;
if (errnum == E2BIG)
{
fprintf(stderr, "%d: got E2BIG (%d: %s) at size %d\n", self, errnum, strerror(errnum), i);
exit(E_GOT_E2BIG);
}
fprintf(stderr, "%d: got errno %d (%s) at size %d\n", self, errnum, strerror(errnum), i);
exit(E_NOT_E2BIG);
}
else
{
int self = getpid();
int corpse;
int status;
int exit_loop = 0;
while ((corpse = waitpid(pid, &status, 0)) != -1)
{
if (!WIFEXITED(status))
printf("%d: child %d died with exit status 0x%.4X", self, corpse, status);
else
{
int statval = WEXITSTATUS(status);
printf("%d: child %d died with exit status %d: ", self, corpse, statval);
switch (statval)
{
case E_GOT_E2BIG:
printf("success: got E2BIG");
exit_loop = 1;
break;
case E_NOT_E2BIG:
printf("failed: indeterminate error in child");
break;
case 1:
printf("command exited with status 1 - it worked");
break;
default:
printf("unknown: unexpected exit status %d", statval);
break;
}
}
printf(" at size %d (%d KiB)\n", i, i / BYTES_PER_KIBIBYTE);
fflush(stdout);
}
if (exit_loop)
break;
}
}
return 0;
}
样本运行:
46573: child 46575 died with exit status 1: command exited with status 1 - it worked at size 4096 (4 KiB)
46573: child 46576 died with exit status 1: command exited with status 1 - it worked at size 8192 (8 KiB)
46573: child 46577 died with exit status 1: command exited with status 1 - it worked at size 16384 (16 KiB)
46573: child 46578 died with exit status 1: command exited with status 1 - it worked at size 32768 (32 KiB)
46573: child 46579 died with exit status 1: command exited with status 1 - it worked at size 65536 (64 KiB)
46573: child 46580 died with exit status 1: command exited with status 1 - it worked at size 131072 (128 KiB)
46581: got E2BIG (7: Argument list too long) at size 262144
46573: child 46581 died with exit status 37: success: got E2BIG at size 262144 (256 KiB)
SIGCHLD 处理代码无关紧要。这是上面代码的更完善的版本。它对参数列表的大小进行二进制搜索。在我的机器 (Mac OS X 10.8.4) 上,考虑到环境(作为参数大小的一部分),限制为 256 KiB。
/* SO 18559403: How big an argument list is allowed */
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
extern char **environ; /* Sometimes in <unistd.h> */
enum { BYTES_PER_KIBIBYTE = 1024 };
enum { BYTES_PER_MEBIBYTE = BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE };
enum { E_GOT_E2BIG = 37 };
enum { E_NOT_E2BIG = 219 };
enum { R_TOO_LARGE = +1, R_TOO_SMALL = -1 };
static char *print_kib(int size, char *buffer, size_t buflen)
{
snprintf(buffer, buflen, "%d (%d KiB)", size, size / BYTES_PER_KIBIBYTE);
return buffer;
}
static int test_arg_size(int size)
{
char buffer[32];
int result = R_TOO_SMALL;
assert(size % 8 == 0);
fflush(0);
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "Failed to fork at size %s\n",
print_kib(size, buffer, sizeof(buffer)));
exit(1);
}
else if (pid == 0)
{
int self = getpid();
printf("Child: %d\n", self);
char *args[10] = { "ls" };
size_t bytes_per_arg = size / 8;
for (int j = 1; j < 9; j++)
{
args[j] = malloc(bytes_per_arg);
if (args[j] == 0)
{
fprintf(stderr, "Failed to allocate argument space at size %s\n",
print_kib(size, buffer, sizeof(buffer)));
exit(E_NOT_E2BIG);
}
memset(args[j], j + '0', bytes_per_arg - 1);
args[j][bytes_per_arg - 1] = '\0';
}
/* Close standard I/O channels so executed command doesn't spew forth */
int dev_null = open("/dev/null", O_RDWR);
if (dev_null < 0)
{
fprintf(stderr, "Failed to open /dev/null for reading and writing\n");
exit(E_NOT_E2BIG);
}
int dev_stderr = dup(2);
if (dev_stderr < 0)
{
fprintf(stderr, "Failed to dup() standard error\n");
exit(E_NOT_E2BIG);
}
close(0);
/*
** GCC on Linux generates warnings if you don't pay attention to
** the value returned by dup().
*/
int fd = dup(dev_null);
assert(fd == 0);
close(1);
fd = dup(dev_null);
assert(fd == 1);
close(2);
fd = dup(dev_null);
assert(fd == 2);
close(dev_null);
/* Execute ls on big file names -- error is ENAMETOOLONG */
execvp(args[0], args);
/* Reinstate standard error so we can report failure */
dup2(dev_stderr, 2);
int errnum = errno;
if (errnum == E2BIG)
{
fprintf(stderr, "%d: got E2BIG (%d: %s) at size %s\n",
self, errnum, strerror(errnum),
print_kib(size, buffer, sizeof(buffer)));
exit(E_GOT_E2BIG);
}
fprintf(stderr, "%d: got errno %d (%s) at size %s\n",
self, errnum, strerror(errnum),
print_kib(size, buffer, sizeof(buffer)));
exit(E_NOT_E2BIG);
}
else
{
int self = getpid();
int corpse;
int status;
while ((corpse = waitpid(pid, &status, 0)) != -1)
{
if (!WIFEXITED(status))
printf("%d: child %d died with exit status 0x%.4X",
self, corpse, status);
else
{
int statval = WEXITSTATUS(status);
printf("%d: child %d died with exit status %d: ",
self, corpse, statval);
switch (statval)
{
case E_GOT_E2BIG:
printf("success: got E2BIG");
result = R_TOO_LARGE;
break;
case E_NOT_E2BIG:
printf("failed: indeterminate error in child");
break;
/*
** ls on Mac OS X fails with 1 if it fails to find a
** file. On Linux, it exits with 1 for 'minor
** problems' (e.g. cannot access subdirectory).
** ls on Linux fails with 2 if it fails with 'serious
** trouble'; (e.g. if it can't find a file)
*/
case 1:
case 2:
printf("command exited with status %d - it worked", statval);
break;
default:
printf("unknown: unexpected exit status %d", statval);
break;
}
}
printf(" at size %s\n", print_kib(size, buffer, sizeof(buffer)));
fflush(stdout);
}
}
return result;
}
static int env_size(void)
{
int size = 0;
for (char **ep = environ; *ep != 0; ep++)
size += strlen(*ep) + 1;
return size;
}
int main(void)
{
int env = env_size();
int lo = 0;
int hi = 4 * BYTES_PER_MEBIBYTE;
/* Binary search */
/* The kilobyte slop means termination does not have to be accurate */
while (lo + 1 * BYTES_PER_KIBIBYTE < hi)
{
int mid = (lo + hi) / 2;
if (test_arg_size(mid) == R_TOO_LARGE)
hi = mid;
else
lo = mid;
}
char buffer1[32];
char buffer2[32];
printf("Environment size = %d\n", env);
printf("Best guess: maximum argument size in range %s to %s\n",
print_kib(lo + env, buffer1, sizeof(buffer1)),
print_kib(hi + env, buffer2, sizeof(buffer2)));
return 0;
}
2014-04-06 更新:在 Linux 上编译和运行更好,其中 ls
区分退出状态 1 和 2 的小问题和严重问题,以及 GCC 所在的位置如果您没有捕获到 dup()
的结果,就会被告知要投诉。还测试最多 4 MiB 参数空间,高于之前的 1 MiB。 (改变 main()
中 hi
的初始值来改变范围。)
注意与二分查找相关的注释;通常,您使用 mid ± 1
来确保搜索的终止,但是当范围为 1 KiB 时此搜索终止并且不弄乱 ±1 使数字“更简单”。并不是说计算机在意——不过我在意。这也是为什么起始范围是 0 MiB .. 1 MiB 而不是 4 KiB .. 1 MiB 的原因;它使数字更清晰。
样本运行:
Child: 71822
71822: got E2BIG (7: Argument list too long) at size 524288 (512 KiB)
71821: child 71822 died with exit status 37: success: got E2BIG at size 524288 (512 KiB)
Child: 71823
71823: got E2BIG (7: Argument list too long) at size 262144 (256 KiB)
71821: child 71823 died with exit status 37: success: got E2BIG at size 262144 (256 KiB)
Child: 71824
71821: child 71824 died with exit status 1: command exited with status 1 - it worked at size 131072 (128 KiB)
Child: 71825
71821: child 71825 died with exit status 1: command exited with status 1 - it worked at size 196608 (192 KiB)
Child: 71826
71821: child 71826 died with exit status 1: command exited with status 1 - it worked at size 229376 (224 KiB)
Child: 71827
71821: child 71827 died with exit status 1: command exited with status 1 - it worked at size 245760 (240 KiB)
Child: 71828
71821: child 71828 died with exit status 1: command exited with status 1 - it worked at size 253952 (248 KiB)
Child: 71829
71821: child 71829 died with exit status 1: command exited with status 1 - it worked at size 258048 (252 KiB)
Child: 71830
71830: got E2BIG (7: Argument list too long) at size 260096 (254 KiB)
71821: child 71830 died with exit status 37: success: got E2BIG at size 260096 (254 KiB)
Child: 71831
71821: child 71831 died with exit status 1: command exited with status 1 - it worked at size 259072 (253 KiB)
Environment size = 2124
Best guess: maximum argument size in range 261196 (255 KiB) to 262220 (256 KiB)
关于c - 检查 exec 中的 E2BIG 错误情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18559403/
我正在创建一个 sql server 存储过程,它将输入作为逗号分隔的 productid 或选项“全部”。当用户传入逗号分隔的产品 ID 时,查询应输出所有产品 ID 的数据。我使用“IN”语句执行
我有一个自动生成的 Web 服务客户端。我有很多复杂的类,我必须对其进行模式匹配。现在我的结构如下所示: val response = client.getResponse response matc
关闭。这个问题是opinion-based .它目前不接受答案。 想改进这个问题?更新问题,以便 editing this post 可以用事实和引用来回答它. 7年前关闭。 Improve this
我需要正确的 tsql 语法来解决这个问题: Select * from table where var_A='10' select * from table where var_B='10' 何时使
我遇到了这个问题。每当我运行程序并在需要时键入字母 m 时,我的 if 语句都不会识别它。有人知道为什么吗?我已经这样做了一个小时,但没有结果。 #include #include #includ
我从数据库列名称“你有护照”创建了一个表,用户回答是或否我如何将 css 应用到这个动态工作的表。 table, th, td { border: 1px solid black;
我对 LocationListener 类的 onStatusChanged 有一些疑问。 它知道它可以呈现三种状态:AVAILABLE、TEMPORARILY_UNAVAILABLE 和 OUT_O
当引入新的异常类型时,我总是不确定如何正确地做到这一点。有共同约定吗?你怎么做呢? 我对您组织它们的范围感兴趣(将它们保留在它们所使用的单元中?在组件级别有一个单元?包级别?应用程序?) 这也会影响命
我使用以下内容创建了日期维度: https://www.codeproject.com/Articles/647950/Create-and-Populate-Date-Dimension-for-D
您好,我正在使用 Android 完全 Kiosk 浏览器,该浏览器使用 chrome Webview。但是 javascript 中的某些方法或函数无法正常工作,例如 window.print()。
我有以下代码: public void OpenFile(string FileName) { if (FileName == null)
获取索引越界异常 for (int recordData = 0; recordData < recordDataList.size(); recordData++) {
我使用它在发生错误时在登录中显示一条消息: × Invalid user or password
这是我的场景,我有一个异常列表,其中包含来自不同层次结构的任意异常,下面的代码快照将解释我需要做什么 private List connectionExceptions; try { // tryin
我尝试动态更新 Jtextpane 中的左缩进。但我不能!这是我尝试过的! DefaultStyledDocument document = (DefaultStyledDocument) textp
我不知道为什么这个异常不起作用...... import java.util.*; public class a { public static void main(String[] args
我目前在 case 中使用多个 when 时遇到问题。当我删除第二个当时,它就起作用了。这是什么问题? 报告的MYSQL错误为: #1064 - You have an error in your S
例如,我有一个表记录用户查看和下载文件的事件, file_id user activity 2 Tim view 1 Ron
这是一个非常愚蠢的问题,但我需要一点安慰/帮助。我有当前的“递归”情况: void add( int value ) { // do something ... // if ( conditi
我尝试使用以下代码在按钮数组上注册回调。但我似乎无法理解如何绑定(bind)回调中需要的字符串。任何建议将不胜感激! for (var i = 0; i < this.car_types.length
我是一名优秀的程序员,十分优秀!