c - Strsep 在我的 Mac OS X x86_64 系统上返回 32 位指针

标签 c macos assembly 32bit-64bit x86-64

编辑:找到解决方案(见底部)

我正在尝试在 Mac OS X 10.8 x86_64 系统上构建软件包 ( owfs )。这个软件包主要是在 Linux 上开发的,但我已经得到了一个旧版本来编译并正确运行,并且互联网上有很多运行它的各种版本的帖子,所以我希望它是可能的。我已经能够成功完成编译过程,但是当我尝试运行程序时,程序会出现段错误。我在 GDB 中进行了调查,结果如下:

有问题的代码:

void FS_dir_entry_aliased(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn)
{
if ( ( pn->state & ePS_unaliased ) == 0 ) {
    // Want alias substituted
    struct parsedname s_pn_copy ;
    struct parsedname * pn_copy = & s_pn_copy ;

    ASCII path[PATH_MAX+3] ;
    ASCII * path_pointer = path ; // current location in original path

    // Shallow copy
    memcpy( pn_copy, pn, sizeof(struct parsedname) ) ;
    pn_copy->path[0] = '\0' ;

    // path copy to use for separation
    strcpy( path, pn->path ) ;

    // copy segments of path (delimitted by "/") to copy
    while( path_pointer != NULL ) {
                    ASCII * path_segment = NULL;
        path_segment = strsep( &path_pointer, "/" ) ;
        BYTE sn[SERIAL_NUMBER_SIZE] ;

        if ( PATH_MAX < strlen(pn_copy->path) + strlen(path_segment) ) {

if block 中调用 strlen(path_segment) 失败,因为 path_segment 是越界地址。

使用 GDB 一步步进行操作,这就是我的发现。进入使用 strsep 初始化 path_segment 的调用,gdb 给出:

path_pointer = (ASCII *) 0x7fff5fbf99a5 "/uncached/bus.0/interface"

执行下一行后,path_pointer 已前进,正如我所期望的:

path_pointer = (ASCII *) 0x7fff5fbf99a6 "uncached/bus.0/interface"

但是 gdb 报告:

path_segment = (ASCII *) 0x5fbf99a5 <Address 0x5fbf99a5 out of bounds>

这是地址的正确“开始”,但它是一个 32 位指针地址。由于我的系统是 64 位系统,因此当调用 strlen 时,我会得到 EXC_BAD_ACCESS。

我知道这里发生了很多事情,如果问题是深埋在包构建过程中的问题,我没有提供足够的信息。在我看来,这可能有一个简单的解决方案,因为该函数基本上工作正常,但只是返回错误的大小指针。不过,我对 64 位与 32 位系统的复杂性缺乏经验,所以我想知道是否有人可以发现一些明显的东西,或者提供调试此问题的后续步骤的说明。有趣的是,当我在 gdb (p (ASCII *) strsep (&path_pointer, "/")) 中手动运行 strsep 命令时,它们似乎工作正常,给了我64 位指针符合我的预期。

最后,如果它有用,下面是我认为的 strsep 调用的 assembly 线:

0x0000000100036eee <FS_dir_entry_aliased+318>:  callq  0x1000a56a0 <dyld_stub_strsep>
0x0000000100036ef3 <FS_dir_entry_aliased+323>:  mov    %eax,%ecx
0x0000000100036ef5 <FS_dir_entry_aliased+325>:  movslq %ecx,%rcx
0x0000000100036ef8 <FS_dir_entry_aliased+328>:  mov    %rcx,-0x1d10(%rbp)

以及该 callq 地址处的 strsep 的反汇编:

0x00007fff915c0fc7 <strsep+0>:  push   %rbp
0x00007fff915c0fc8 <strsep+1>:  mov    %rsp,%rbp
0x00007fff915c0fcb <strsep+4>:  mov    (%rdi),%r8
0x00007fff915c0fce <strsep+7>:  xor    %eax,%eax
0x00007fff915c0fd0 <strsep+9>:  test   %r8,%r8
0x00007fff915c0fd3 <strsep+12>: je     0x7fff915c1007 <strsep+64>
0x00007fff915c0fd5 <strsep+14>: mov    %r8,%r10
0x00007fff915c0fd8 <strsep+17>: jmp    0x7fff915c0fe4 <strsep+29>
0x00007fff915c0fda <strsep+19>: inc    %rdx
0x00007fff915c0fdd <strsep+22>: test   %al,%al
0x00007fff915c0fdf <strsep+24>: jne    0x7fff915c0fee <strsep+39>
0x00007fff915c0fe1 <strsep+26>: mov    %r9,%r10
0x00007fff915c0fe4 <strsep+29>: mov    (%r10),%cl
0x00007fff915c0fe7 <strsep+32>: lea    0x1(%r10),%r9
0x00007fff915c0feb <strsep+36>: mov    %rsi,%rdx
0x00007fff915c0fee <strsep+39>: mov    (%rdx),%al
0x00007fff915c0ff0 <strsep+41>: cmp    %cl,%al
0x00007fff915c0ff2 <strsep+43>: jne    0x7fff915c0fda <strsep+19>
0x00007fff915c0ff4 <strsep+45>: xor    %edx,%edx
0x00007fff915c0ff6 <strsep+47>: test   %cl,%cl
0x00007fff915c0ff8 <strsep+49>: je     0x7fff915c1001 <strsep+58>
0x00007fff915c0ffa <strsep+51>: movb   $0x0,(%r10)
0x00007fff915c0ffe <strsep+55>: mov    %r9,%rdx
0x00007fff915c1001 <strsep+58>: mov    %rdx,(%rdi)
0x00007fff915c1004 <strsep+61>: mov    %r8,%rax
0x00007fff915c1007 <strsep+64>: pop    %rbp
0x00007fff915c1008 <strsep+65>: retq

编辑: string.h 肯定被包含在内,有一个系统范围的包含文件包含它,但只是为了确保我尝试将其添加到这个特定文件中。 -D_BSD_SOURCE=1 是自动添加的编译器选项之一,因此正在发生这种情况。默认情况下还有一个编译器选项 -D_ISOC99_SOURCE=1。我尝试添加 -std=gnu99 (我的编译器 llvm-gcc 4.2,不喜欢 -std=gnu90),但它没有修复它。我收到以下编译器错误:

以下是我收到的此文件的编译器警告:

ow_alias.c: In function 'ReadAliasFile':
ow_alias.c:40: warning: implicit declaration of function 'getline'
ow_alias.c:48: warning: implicit declaration of function 'strsep'
ow_alias.c:48: warning: assignment makes pointer from integer without a cast
ow_alias.c:64: warning: assignment makes pointer from integer without a cast
ow_alias.c: In function 'FS_dir_entry_aliased':
ow_alias.c:177: warning: initialization makes pointer from integer without a cast

第二次编辑: 经过进一步挖掘(感谢 gcc -E | grep strsep 提示!),我发现问题出在编译器标志 -D_POSIX_C_SOURCE=200112L 上。此编译器标志阻止了 strsep 的定义,使编译器做出隐式声明。我从配置脚本中删除了它,一切似乎都工作正常。感谢您的帮助!

最佳答案

您需要确保包含 string.h

如果这已经完成,您还需要定义一个功能测试宏来启用 strsep() 的声明。添加 -D_GNU_SOURCE-D_BSD_SOURCE 应该可以解决问题。但是,您可能想了解一下现在的配置方式 - _BSD_SOURCE 通常默认启用。也许您告诉 gcc 使用 -std=c90-std=c99 进行编译,这将关闭许多功能测试宏。请改用 -std=gnu90-std=gnu99

您是否看到诸如“初始化从整数生成指针而不进行强制转换”或“隐式函数声明”之类的警告?

关于c - Strsep 在我的 Mac OS X x86_64 系统上返回 32 位指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13834222/

相关文章:

c - Argc/Argv C 问题

c - 重温 C 中的字符串数组初始化

c - 如何知道传递给函数的 char 数组的大小(以字节为单位)?

database - Secure Database For Mac OS Xdevelopment(特别是核心数据)有哪些选项?

java - PrintWriter 默认位置

c - SIC 汇编程序 I/O

编译器独立的表达式算术转换和整数提升

c - 如何使用 execl ("/usr/bin/open"...) 重新启动 macOS 中的当前程序?

assembly - MIPS 组装中的奇怪跳跃

assembly - 为什么需要内存对齐?