我想使用第三方函数,它通过充满函数指针的结构提供其 API。例如:
struct S {
using p_func1 = int(*)(int, int);
p_func1 func1;
using p_func2 = int(*)(char*);
p_func2 func2;
}
Run Code Online (Sandbox Code Playgroud)
第三方库初始化该结构。需要检查这些函数(func1、func2)的返回值,我希望能够以某种方式在属性上体现出来,[[discard]]以确保返回值得到检查。
有什么办法可以做到这一点,同时保持结构的 ABI?
编辑:到目前为止,我能想到的最好的办法就是拥有另一个结构,如下所示:
struct S_wrap {
S orig;
[[nodiscard]] int func1(int a, int b){ return orig.func1(a, b); }
[[nodiscard]] int func2(char* a){ return orig.func2(a); }
}
Run Code Online (Sandbox Code Playgroud)
我希望有更好的东西
由于 Spectre 缓解,所有当前 CPU 都禁用了硬件锁定省略是否正确,并且任何尝试使用 HLE 内在函数/指令进行互斥都会导致通常的互斥?
这是否有可能在未来不会有类似 HLE 互斥体的东西来避免像 Spectre 这样的漏洞?
C++20std::barrier有arrive_and_wait方法,这几乎是每个同步屏障实现都有的。
但它也有单独的arrive和wait。为什么会有这些功能?
TL:DR:如果互斥体实现使用获取和释放操作,那么实现是否可以像通常允许的那样进行编译时重新排序,并重叠两个应该独立于不同锁的临界区?这将导致潜在的僵局。
假设互斥锁在 上实现std::atomic_flag:
struct mutex
{
void lock()
{
while (lock.test_and_set(std::memory_order_acquire))
{
yield_execution();
}
}
void unlock()
{
lock.clear(std::memory_order_release);
}
std::atomic_flag lock; // = ATOMIC_FLAG_INIT in pre-C++20
};
Run Code Online (Sandbox Code Playgroud)
到目前为止看起来还可以,关于使用单个这样的互斥锁:std::memory_order_release与std::memory_order_acquire.
在这里使用std::memory_order_acquire/std::memory_order_release不应该一见钟情。它们类似于 cppreference 示例https://en.cppreference.com/w/cpp/atomic/atomic_flag
现在有两个互斥锁保护不同的变量,两个线程以不同的顺序访问它们:
mutex m1;
data v1;
mutex m2;
data v2;
void threadA()
{
m1.lock();
v1.use();
m1.unlock();
m2.lock();
v2.use();
m2.unlock();
}
void threadB()
{
m2.lock();
v2.use();
m2.unlock();
m1.lock();
v1.use();
m1.unlock();
}
Run Code Online (Sandbox Code Playgroud)
释放操作可以在无关的获取操作之后重新排序(无关操作 == 对不同对象的后续操作),因此执行可以转换如下:
mutex m1;
data v1;
mutex …Run Code Online (Sandbox Code Playgroud) C++17具有nodiscard防止人们忽略函数返回值的属性。
将其添加到代码库中的每个函数中似乎有些过分了。
是否有一个标志告诉 Clang 默认强制执行此操作?
我假设简单的自旋锁不会进入操作系统等待这个问题的目的。
我发现简单的自旋锁通常使用lock xchgorlock bts代替 来实现lock cmpxchg。
cmpxchg但是如果期望不匹配,是否会避免写入该值?那么失败的尝试不是更便宜吗cmpxchg?
或者即使cmpxchg发生故障也会写入数据并使其他核心的缓存线无效?
这个问题类似于什么具体将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?,但它是特定的cmpxchg,而不是普遍的。
我想将一个类标记为 nodiscard,但将某个函数的返回值排除在 nodiscard 要求之外。这是我的目标:
enum class [[nodiscard]] Result {
OK1,
OK2,
ERROR,
};
[[ok-to-discard]] // This attribute is made up to illustrate my need.
Result doSomethingThatCannotFail() {
// The function can return OK1 or OK2, but the caller may or may not care.
// The function cannot return ERROR.
// Therefore, it's OK to discard this particular Result return value,
// even though in general Result should not be ignored.
}
Run Code Online (Sandbox Code Playgroud)
我不认为在每个调用站点添加 ok-to-discard 是一个好主意(这由 如何故意丢弃 [[nodiscard]] 返回值? 涵盖):
我正在尝试一个使用 Qt 和 MSVC 2019 以及 Address Sanitizer 的项目。我使用 Address Sanitizer 构建了该项目,但没有重建所有库,包括 Qt。
qRegisterResourceData它在资源初始化(在调用堆栈中)时在 Qt 内部崩溃。
这是:
我已经在默认情况下由向导创建的小部件应用程序中重新创建了该问题。调用栈如下:
> KernelBase.dll!RaiseException() Unknown
QtWidgetsApplication1.exe!__vcasan::OnAsanReport(const char * description, const char * report, bool __throw) Line 602 C++
QtWidgetsApplication1.exe!__vcasan::ReportCallback(const char * szReport) Line 325 C++
clang_rt.asan_dbg_dynamic-x86_64.dll!__asan::ScopedInErrorReport::~ScopedInErrorReport(void) Unknown
clang_rt.asan_dbg_dynamic-x86_64.dll!__asan::ReportMallocUsableSizeNotOwned(unsigned __int64,struct __sanitizer::BufferedStackTrace *) Unknown
clang_rt.asan_dbg_dynamic-x86_64.dll!__asan::asan_malloc_usable_size(void const *,unsigned __int64,unsigned __int64) Unknown
clang_rt.asan_dbg_dynamic-x86_64.dll!_recalloc() Unknown
ucrtbased.dll!_register_onexit_function::__l2::<lambda>() Line 112 C++
ucrtbased.dll!__crt_seh_guarded_call<int>::operator()<void <lambda>(void),int <lambda>(void) &,void <lambda>(void)>(__acrt_lock_and_call::__l2::void <lambda>(void) && setup, _register_onexit_function::__l2::int <lambda>(void) & …Run Code Online (Sandbox Code Playgroud) 我认为热补丁假设用 2 字节跳转覆盖任何 2 或更多字节长的指令对于并发执行相同的代码是安全的。
因此取指令被假定为原子的。
考虑到使用前缀可以有超过 8 字节的指令,并且它可以跨越任何对齐的边界,它确实是原子的吗?(或者热补丁是否依赖于函数开始的 16 字节对齐?如果是这样,那么大小超过 8 字节又是什么?)
上下文:LLVM 在https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/interception/interception_win.cpp中拦截了 API 函数。这至少用于 Address Sanitizer,也许也用于其他用途。它将 HotPatch 实现为第三种方法(第 61 行):
// 3) HotPatch
//
// The HotPatch hooking is assuming the presence of an header with padding
// and a first instruction with at least 2-bytes.
//
// The reason to enforce the 2-bytes limitation is to provide the minimal
// space to encode a short jump. HotPatch technique is only rewriting one …Run Code Online (Sandbox Code Playgroud) 英特尔建议使用指令前缀来减轻 JCC 勘误对性能的影响。
如果使用 MSVC 进行编译,则会/QIntel-jcc-erratum遵循建议,并插入带前缀的指令,如下所示:
3E 3E 3E 3E 3E 3E 3E 3E 3E 48 8B C8 mov rcx,rax ; with redundant 3E prefixes
Run Code Online (Sandbox Code Playgroud)
他们说,当前缀不可用时,MSVC 会求助于 NOP。
Clang 有-mbranches-within-32B-boundaries这个选项,nop如果需要,它更喜欢多字节(https://godbolt.org/z/399nc5Msq通知xchg ax, ax)
3E 前缀的后果是什么,具体来说:
/QIntel-jcc-erratum,可能的解释是什么?