小编R..*_*R..的帖子

为已弃用的函数生成链接时错误

是否有一种方法可以使用gcc和GNU binutils来标记某些函数,以便它们在链接时生成错误(如果使用的话)?我的情况是我有一些库函数,我不是为了与现有的二进制文件兼容而删除,但我想确保没有新编译的二进制文件尝试使用这些函数.我不能只使用编译时gcc属性,因为违规代码忽略了我的标题,并用configure脚本检测函数的存在并自己进行原型设计.我的目标是为坏configure脚本生成链接时错误,以便它们停止检测函数的存在.

编辑:一个想法..将使用程序集指定.type入口点的错误与动态链接器兼容但在尝试链接新程序时生成链接错误?

c linker gcc binutils

6
推荐指数
1
解决办法
785
查看次数

mbrtowc的s == NULL情况的目的是什么?

mbrtowc被指定为处理NULL用于指针s(多字节字符指针)参数,如下所示:

如果s是空指针,则mbrtowc()函数应等效于调用:

mbrtowc(NULL, "", 1, ps)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,将忽略参数pwc和n的值.

据我所知,这种用法基本上没用.如果ps没有存储任何部分转换的字符,则调用将返回0而没有副作用.如果ps正在存储的局部转换的字符,则因为'\0'是无效的,如一个多字节序列的下一个字节('\0'只能是一个字符串结束),则调用将返回(size_t)-1errno==EILSEQ.并ps处于未定义的状态.

预期的用法似乎是重置状态变量,特别是当NULL传递ps状态并且已经使用了内部状态时,类似于mbtowc有状态编码的行为,但就我所知,这在任何地方没有指定,并且它与mbrtowc存储部分转换字符的语义冲突(如果mbrtowc在潜在有效的初始子序列之后遇到0字节时重置状态,则无法检测到这种危险的无效序列).

如果mbrtowc指定仅在sis 时重置状态变量NULL,而不是在指向0字节时重置状态变量,则可能出现所需的状态重置行为,但这种行为将违反所写的标准.这是标准中的缺陷吗?据我所知,是绝对没有办法复位内部状态(使用时psNULL)一旦非法序列已经遇到过,因此没有正确的程序可以使用mbrtowcps==NULL.

c standards multibyte language-lawyer

6
推荐指数
1
解决办法
565
查看次数

用于GNU make的Backtrace

有没有办法让GNU make打印导致命令失败时执行的目标的"回溯"?我经常处理严重混淆的makefile,同时解决在新系统上构建软件的可移植性问题,看起来这对于make来说应该是一个非常简单的事情,这将极大地帮助调试,但我找不到任何方式来请求它.我希望看到的是:

gcc: error: ...
make[2]: error: gcc ...
make[2]: error building target bar
make[2]: error building dependency bar for target foo
make[1]: error: make -C subdir
make[1]: error building target subdir
make[1]: error building dependency subdir for target all
...
Run Code Online (Sandbox Code Playgroud)

显示失败命令最终执行的整个依赖路径.

有没有办法做到这一点?

c makefile gnu-make

6
推荐指数
1
解决办法
1356
查看次数

可以进行短读/写的条件是什么?

readwrite功能(和亲戚一样send,recv,readv,...)可以在其他情况下,返回一个数字小于所请求的读/写字节长度,如果信号中断(在某些情况下),也许太.是否存在明确定义的条件,以确定何时会发生这种情况,还是在很大程度上取决于实施?以下是我对以下答案感兴趣的一些特殊问题:

  • 如果信号处理程序是非中断(SA_RESTART),则会在信号处理程序返回后重新传输任何数据之前导致IO操作中断.但是如果已经发生了部分读/写并且信号处理程序是非中断的,那么系统调用是否会立即以部分长度返回,还是会恢复尝试读/写余数?
  • 显然,当可用的数据少于请求数量时,读取函数可以返回网络,管道和终端文件描述符上的短读取.但是由于缓冲区大小有限,写入函数可以在这些情况下返回短写入,还是会阻塞直到所有数据都被写入?

我会对所有三种标准 - 所需,常见和特定于Linux的行为感兴趣.

c posix signals

6
推荐指数
1
解决办法
438
查看次数

pthread_atfork 锁定习惯用法坏了?

标准用法pthread_atfork应该是在 pre-fork 处理程序中获取所有锁,并在父处理程序和子处理程序中释放它们。然而,据我所知,这是不可能的。pthread_mutex_unlock如果调用线程不是互斥锁的所有者,则指定为具有未定义的行为(在正常或默认类型互斥锁的情况下)或失败(在递归或错误检查互斥锁的情况下)。并且在注册的子处理程序中pthread_atfork,调用线程是新创建进程的主线程,因此不能是互斥锁的所有者。

是我弄错了还是整个pthread_atfork习语被设计破坏了并且基本上无法使用?

编辑:我也没有看到针对该问题的任何有效(便携式)解决方法。理想情况下,可以在子进程中销毁并重新初始化互斥锁,除了调用pthread_mutex_destroy已初始化的互斥锁被指定为未定义行为,以适应其中互斥锁不是 POD 但涉及对某些内核级对象的引用的荒谬实现。

c posix fork pthreads

6
推荐指数
1
解决办法
571
查看次数

在strtol等人的规范中混淆语言

strtol概念上,规范将输入字符串分为"初始空格","主题序列"和"最终字符串",并将"主题序列"定义为:

输入字符串的最长初始子序列,从第一个具有预期形式的非空白字符开始.如果输入字符串为空或完全由空格字符组成,或者第一个非空白字符不是符号或允许的字母或数字,则主题序列不应包含任何字符.

有一次,我认为"最长的初始子序列"业务类似于scanf工作方式,在哪里"0x@"扫描"0x",失败的匹配,然后"@"作为下一个未读的角色.然而,在经过一些讨论之后,我基本上确信strtol处理了预期形式的最长初始子序列,而不是最长的初始字符串,它是预期形式的某些可能字符串的初始子序列.

令我困惑的是规范中的这种语言:

如果主题序列为空或者没有预期的形式,则不进行转换; str的值存储在endptr指向的对象中,前提是endptr不是空指针.

如果我们接受似乎是"主题序列"的正确定义,那么就没有不具有预期形式的非空主题序列,而是(为了避免冗余和混淆)文本应该只读:

如果主题序列为空,则不执行转换; str的值存储在endptr指向的对象中,前提是endptr不是空指针.

谁能为我澄清这些问题?也许与过去的讨论或任何相关缺陷报告的链接将是有用的.

c standards-compliance language-lawyer strtol

6
推荐指数
1
解决办法
226
查看次数

Linux futex系统调用虚假唤醒,返回值为0?

我遇到了Linux futex系统调用(FUTEX_WAIT操作)的问题,有时候看起来很早就没有原因.文档指定了可能导致它提前返回的某些条件(没有a FUTEX_WAKE),但这些条件都涉及非零返回值:EAGAIN如果futex地址的值不匹配,则ETIMEDOUT定时等待超时,EINTR当被a(非但是我看到返回值为0.除了指针指向futex FUTEX_WAKE的线程的终止之外,返回值为0的原因是什么?set_tid_addressFUTEX_WAIT

如果它有用,我正在等待的特定futex是线程tid地址(由clonesyscall 设置CLONE_CHILD_CLEARTID),并且线程没有终止.我的(显然是不正确的)假设FUTEX_WAIT操作返回0只能在线程终止时导致程序逻辑出现严重错误,我已经通过循环和重试来修复,即使它返回0,但现在我很好奇为什么会这样.

这是一个最小的测试用例:

#define _GNU_SOURCE
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <linux/futex.h>
#include <signal.h>

static char stack[32768];
static int tid;

static int foo(void *p)
{
        syscall(SYS_getpid);
        syscall(SYS_getpid);
        syscall(SYS_exit, 0);
}

int main()
{
        int pid = getpid();
        for (;;) {
                int x = clone(foo, stack+sizeof stack,
                        CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND
                        |CLONE_THREAD|CLONE_SYSVSEM //|CLONE_SETTLS
                        |CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID
                        |CLONE_DETACHED,
                        0, &tid, 0, …
Run Code Online (Sandbox Code Playgroud)

c linux futex

6
推荐指数
1
解决办法
2053
查看次数

何时可以使用cond var来同步自己的销毁/取消映射?

根据POSIX,

销毁当前没有线程被阻塞的初始化条件变量应该是安全的.

此外,指定信号和广播操作以解除阻塞在条件变量上阻塞的一个/所有线程.

因此,在我看来,以下形式的自同步破坏应该是有效的,即pthread_cond_destroy:

  1. 在成功的信号之后,在等待或信令线程中,当cond var上只有一个线程被阻塞时.
  2. 在成功广播之后,立即在任何等待线程或广播线程中.

当然,假设没有其他服务员到达,之后不再执行任何信号,如果使用,应用程序负责保证pthread_cond_destroy.

我是否认为破坏在这些情况下是有效的?还有其他自我同步的破坏场景需要注意条件变量吗?

最后,对于在没有破坏的情况下取消映射共享映射的进程共享cond变量可能是有意义的,期望取消映射在相同的上下文中有效是合理的,破坏是有效的,或者如果同一进程中的多个线程必须进一步同步(地址空间)使用相同的映射,并希望在上述某个上下文中取消映射?

c synchronization posix pthreads condition-variable

6
推荐指数
1
解决办法
695
查看次数

使用GLOB_MARK的glob是否应附加/到symlink-to-directory结果?

glob函数有一个GLOB_MARK标志,指定为对目标结果附加斜杠:

GLOB_MARK

作为匹配模式的目录的每个路径名都应<slash>附加一个.

(来源:http://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html)

但是,据我所知,没有提供有关此功能如何工作的更多详细信息.特别是,如果结果本身不是目录,而是目录的符号链接,是否应该附加斜杠?glibc实现就是这样做的.

我知道这是一个难以回答的问题,因为标准的简洁性glob,所以很好的答案将引用历史实践,历史标准或POSIX以外的文档,可能进一步指明行为glob等.提出理由的答案为什么一种行为或另一种行为更有用也会很有趣.

c posix glob language-lawyer

6
推荐指数
1
解决办法
382
查看次数

如何广泛支持pragma weak,它是否克服了使用gcc属性的问题?

我刚刚#pragma weak在GCC中发现了该指令:

6.57.9弱的语用

为了与SVR4兼容,GCC支持一组#pragma指令,用于声明符号弱,并定义弱别名.

#pragma weak symbol

该pragma声明符号为弱,就好像声明具有相同名称的属性一样.该编译指示可能出现在符号声明之前或之后.符号永远不会被定义,这不是错误.

#pragma weak symbol1 = symbol2

该pragma将symbol1声明为symbol2的弱别名.如果未在当前转换单元中定义symbol2,则会出错.

http://gcc.gnu.org/onlinedocs/gcc/Weak-Pragmas.html

尽管GCC开发人员通常不喜欢#pragma并鼓励您使用__attribute__可能是pragma的各种事物,但我倾向于认为#pragma weak可能实际上优于基于属性的方法,它看起来像:

extern __typeof(old_name) new_name __attribute__(weak, alias("old_name"))
Run Code Online (Sandbox Code Playgroud)

除了要求的丑陋__typeof(或要求你知道的类型和拼写出来明确,即使这是一个非常复杂的函数类型),属性为基础的方法最大的问题是,"old_name"必须通过与gcc 作为一个字符串是从字面上粘贴到生成的程序集中.这是有问题的,因为不同的系统具有不同的名称修改特性(最流行的是在所有C符号名称前加下划线,或根本不执行任何操作),并且要将正确的字符串传递给alias属性,您需要知道名称修改约定您正在构建的系统,这实际上不是属于应用程序级库的知识,其中弱别名可能有用.

语法#pragma weak new_name = old_name似乎通过在编译器级别处理这两个名称来避免这个问题,其中t可以适当地修改它们,除非我弄错了.

所有的预赛都完成后,我的实际问题是:我是否错误地认为#pragma weak这具有"便携性"优势?并且所有类似unix的系统上的现代编译器(gcc,pcc,tinycc,icc,llvm/clang等)是否仍然支持传统的SVR4 #pragma weak

我知道以下类似的问题,但它似乎并不完全相同,答案不能令人满意地解决我的问题:

弱连接的便携性如何?#pragma weak my_symbol

c gcc pragma

6
推荐指数
1
解决办法
3214
查看次数