Android、CMDTool、标准输出重定向、"Fatal signal 11 (SIGSEGV)"
Android, CMDTool, stdout redirect, "Fatal signal 11 (SIGSEGV)"
用例
Android C++ 命令行工具使用“/system/bin/getprop”并将其标准输出重定向到套接字
问题
午餐 'getprop' 失败并显示 "F/libc (20694): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 20694 (getprop)",代码和 logcat 片段如下。
为什么我得到 SIGSEGV?为什么分叉进程失败?
实施
HRESULT ServiceCore::CreateProcessAndRedirectStdout(IN char* pCmd, IN char** args, OUT SOCKET& stdoutstream) {
HRESULT hr = S_OK;
int fds[2] = { 0 };
pid_t pid = 0;
stdoutstream = 0;
if (SOCKET_ERROR == socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
goto ErrExit;
stdoutstream = fds[1];
if((pid = fork()) < 0)
goto ErrExit;
if (pid == 0) {
// The newly created process
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s' started", pCmd);
int newfd = dup2(fds[0], STDOUT_FILENO);
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s' newfd:%d, oldfd:%d", pCmd, newfd, fds[0]);
_ASSERT(newfd == STDOUT_FILENO);
close(fds[0]);
close(fds[1]);
execvp(pCmd, args);
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s' FAILED", pCmd);
exit(1);
}
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s(%d)' Created", pCmd, pid);
return S_OK;
ErrExit:
if (0 != pid)
kill(pid, SIGTERM);
close(fds[0]);
close(fds[1]);
stdoutstream = 0;
return hr;
}
...
char* args[] = { 0 };
SOCKET soc;
if (SUCCEEDED(hr = CreateProcessAndRedirectStdout("/system/bin/getprop", args, soc))) {
errno = 0;
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "SendConfig>> Reading props");
char pTmp[256000];
int iRet = read(soc, pTmp, sizeof(pTmp));// Read the first few lines
}
...
logcat
I/ServiceCore(20689): CreateProcessAndRedirectStdout>> '/system/bin/getprop(20694)' Created
I/ServiceCore(20689): SendConfig>> Reading props
I/ServiceCore(20694): CreateProcessAndRedirectStdout>> '/system/bin/getprop' started
I/ServiceCore(20694): CreateProcessAndRedirectStdout>> '/system/bin/getprop' newfd:1, oldfd:10
F/libc (20694): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 20694 (getprop)
您以 getprop
未编写处理的方式滥用 execvp()。引用 execvp()
的 OSX/BSD(但实际上是通用的)手册页
The execv(), execvp(), and execvP() functions provide an array of pointers to null-terminated strings that represent the argument list available
to the new program. The first argument, by convention, should point to
the file name associated with the file being executed. The array of
pointers must be terminated by a NULL pointer.
您通过传递一个 NULL 元素的数组打破了这个约定,而 您应该将程序名称作为第一个元素传递,然后是终止 NULL 元素。
这将 getprop
设置为失败,因为它考虑了只有一个参数(本身)的可能性,在这种情况下它将显示所有内容。
if (argc == 1) {
list_properties();
但如果它没有 1 个参数,它 假定 它必须有两个或更多,并尝试取消引用第二个, 应该 是您要获取的 属性 的名称。
property_get(argv[1], value, default_value);
将无效且可能为空的指针代替 属性 名称传递给 property_get() 最终会在仿生 libc 的深处失败,可能是 __system_property_find() 调用的实现strlen().
如果您按照 fadden 的建议检查了堆栈跟踪,您可能会在 libc 中看到一个地址,可能是 strlen()。
用例
Android C++ 命令行工具使用“/system/bin/getprop”并将其标准输出重定向到套接字
问题
午餐 'getprop' 失败并显示 "F/libc (20694): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 20694 (getprop)",代码和 logcat 片段如下。
为什么我得到 SIGSEGV?为什么分叉进程失败?
实施
HRESULT ServiceCore::CreateProcessAndRedirectStdout(IN char* pCmd, IN char** args, OUT SOCKET& stdoutstream) {
HRESULT hr = S_OK;
int fds[2] = { 0 };
pid_t pid = 0;
stdoutstream = 0;
if (SOCKET_ERROR == socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
goto ErrExit;
stdoutstream = fds[1];
if((pid = fork()) < 0)
goto ErrExit;
if (pid == 0) {
// The newly created process
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s' started", pCmd);
int newfd = dup2(fds[0], STDOUT_FILENO);
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s' newfd:%d, oldfd:%d", pCmd, newfd, fds[0]);
_ASSERT(newfd == STDOUT_FILENO);
close(fds[0]);
close(fds[1]);
execvp(pCmd, args);
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s' FAILED", pCmd);
exit(1);
}
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "CreateProcessAndRedirectStdout>> '%s(%d)' Created", pCmd, pid);
return S_OK;
ErrExit:
if (0 != pid)
kill(pid, SIGTERM);
close(fds[0]);
close(fds[1]);
stdoutstream = 0;
return hr;
}
...
char* args[] = { 0 };
SOCKET soc;
if (SUCCEEDED(hr = CreateProcessAndRedirectStdout("/system/bin/getprop", args, soc))) {
errno = 0;
__android_log_print(ANDROID_LOG_INFO, "ServiceCore", "SendConfig>> Reading props");
char pTmp[256000];
int iRet = read(soc, pTmp, sizeof(pTmp));// Read the first few lines
}
...
logcat
I/ServiceCore(20689): CreateProcessAndRedirectStdout>> '/system/bin/getprop(20694)' Created
I/ServiceCore(20689): SendConfig>> Reading props
I/ServiceCore(20694): CreateProcessAndRedirectStdout>> '/system/bin/getprop' started
I/ServiceCore(20694): CreateProcessAndRedirectStdout>> '/system/bin/getprop' newfd:1, oldfd:10
F/libc (20694): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 20694 (getprop)
您以 getprop
未编写处理的方式滥用 execvp()。引用 execvp()
The execv(), execvp(), and execvP() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program. The first argument, by convention, should point to the file name associated with the file being executed. The array of pointers must be terminated by a NULL pointer.
您通过传递一个 NULL 元素的数组打破了这个约定,而 您应该将程序名称作为第一个元素传递,然后是终止 NULL 元素。
这将 getprop
设置为失败,因为它考虑了只有一个参数(本身)的可能性,在这种情况下它将显示所有内容。
if (argc == 1) {
list_properties();
但如果它没有 1 个参数,它 假定 它必须有两个或更多,并尝试取消引用第二个, 应该 是您要获取的 属性 的名称。
property_get(argv[1], value, default_value);
将无效且可能为空的指针代替 属性 名称传递给 property_get() 最终会在仿生 libc 的深处失败,可能是 __system_property_find() 调用的实现strlen().
如果您按照 fadden 的建议检查了堆栈跟踪,您可能会在 libc 中看到一个地址,可能是 strlen()。