layout | title |
---|---|
post |
第177期 |
公众号
点击「查看原文」跳转到 GitHub 上对应文件,链接就可以点击了
qq群 点击进入 满了加这个 729240657
欢迎投稿,推荐或自荐文章/软件/资源等,评论区留言
本期文章由 F.v.S
祥子
Jared
赞助 在此表示感谢
祝大家新年快乐。又要返工了
标准委员会动态/ide/编译器信息放在这里 c++26最新进展可以看这个帖子
编译器信息最新动态推荐关注hellogcc公众号 本周更新 2025-01-08 第288期
结构化绑定的参数可以标记属性attr,比如
std::map<int, std::string> m{
{1, "one"}, {2, "two"} {3, "three"}};
for(const auto& [ [[maybe_unused]] k, v]: m) {
DEBUG(k) // only used in debug builds
std::cout << v << '\n';
}
通过返回值复制,而不是手动赋值。规避潜在的多余构造
std::mutex m_mutex;
Widget m_widget;
// Get a copy of the widget
Widget widget;
{
auto guard = std::lock_guard(m_mutex);
widget = m_widget;
}
这是常规写法,不好。倾向于通过返回值一次赋值
// Get a copy of the widget
Widget widget = [&] {
auto guard = std::lock_guard(m_mutex);
return m_widget;
}();
这种lambda用的多了你也可以通过封装函数来返回
Widget CopySavedWidget()
{
auto guard = std::lock_guard(m_mutex);
return m_widget;
}
类似的保存-销毁需求
Widget widget = [&] {
auto guard = std::lock_guard(m_mutex);
return std::exchange(m_widget, {});
}();
也可以这样封装,更泛化一点
template<typename T>
Widget ExchangeSavedWidget(T&& value)
{
auto guard = std::lock_guard(m_mutex);
return std::exchange(m_widget, std::forward<T>(value)):
}
鉴赏几个PPSSPP项目的bug
static int sceNetAdhocctlGetAddrByName(const char *nickName,
u32 sizeAddr, u32 bufAddr)
{
....
// Copied to null-terminated var to prevent unexpected behaviour on Logs
memcpy(nckName, nickName, ADHOCCTL_NICKNAME_LEN);
....
if (netAdhocctlInited)
{
// Valid Arguments
if (nickName != NULL && buflen != NULL)
{
....
}
....
}
}
如果if里的nickName存在等于nullptr的可能,那么memcpy的行为会有UB,那么这个代码必然有问题了
int internal_profiler_find_cat(const char *category_name, bool create_missing)
{
int i;
for (i = 0; i < MAX_CATEGORIES; i++)
{
const char *catname = categories[i].name;
if (!catname)
break;
#ifdef UNIFIED_CONST_STR
if (catname == category_name)
{
#else
if (!strcmp(catname, category_name)) // <=
{
#endif
return i;
}
}
if (i < MAX_CATEGORIES && category_name && create_missing) // <=
{
....
}
}
没有检查category_name是不是nullptr就放到strcmp里,潜在bug
static void __GameModeNotify(u64 userdata, int cyclesLate)
{
....
if (gameModeSocket < 0)
{
// ReSchedule
CoreTiming::ScheduleEvent(usToCycles(GAMEMODE_UPDATE_INTERVAL) - cyclesLate,
gameModeNotifyEvent, userdata);
return;
}
auto sock = adhocSockets[gameModeSocket - 1];
....
}
数组索引可能是-1
SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
: GPUCommon(gfxCtx, draw)
{
....
drawEngine_ = new SoftwareDrawEngine();
if (!drawEngine_)
return;
....
}
这个指针检查屁用没有,new不出来会抛异常。如果在意就用catch兜住啊
static std::vector<MicWaitInfo> waitingThreads;
....
static void __MicBlockingResume(u64 userdata, int cyclesLate)
{
....
int count = 0;
for (auto waitingThread : waitingThreads)
{
if (waitingThread.threadID == threadID)
{
....
if (Microphone::isHaveDevice())
{
if (Microphone::getReadMicDataLength() >= waitingThread.needSize)
{
....
waitingThreads.erase(waitingThreads.begin() + count); // <=
}
else
{
....
}
}
else
{
....
waitingThreads.erase(waitingThreads.begin() + count); // <=
readMicDataLength += waitingThread.needSize;
}
}
++count;
}
}
经典问题,循环中删除
void Int_VecDo3(MIPSOpcode op)
{
....
u32 lastsat = (currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] & 3) << (n + n - 2);
....
}
n + n -2可能是负数 <<就UB了
inline float Float16ToFloat(float16 ix)
{
float x;
memcpy(&x, &ix, sizeof(float));
return x;
}
复制越界
void Jit::Comp_SVQ(MIPSOpcode op)
{
CONDITIONAL_DISABLE(LSU_VFPU);
int imm = (signed short)(op&0xFFFC);
int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5);
MIPSGPReg rs = _RS;
CheckMemoryBreakpoint(0, rs, imm);
switch (op >> 26)
{
case 53: //lvl.q/lvr.q
{
if (!g_Config.bFastMemory)
{
DISABLE;
}
DISABLE;
....
}
代码语义重复 DISABLE无论如何都能走到
void BlockAllocator::Block::DoState(PointerWrap &p)
{
char tag[32];
....
size_t tagLen = strlen(tag);
if (tagLen != sizeof(tag))
memset(tag + tagLen, 0, sizeof(tag) - tagLen);
DoArray(p, tag, sizeof(tag));
}
多余的if分支,永远true
void netAdhocValidateLoopMemory()
{
// Allocate Memory if it wasn't valid/allocated
// after loaded from old SaveState
if ( !dummyThreadHackAddr
|| ( dummyThreadHackAddr
&& strcmp("dummythreadhack",
kernelMemory.GetBlockTag(dummyThreadHackAddr)) != 0))
{
....
}
条件重复
void QueueCallback(void (*func)(VulkanContext *vulkan, void *userdata),
void *userdata)
{
callbacks_.push_back(Callback(func, userdata));
}
void VulkanRenderManager::EndCurRenderStep()
{
for (VKRGraphicsPipeline *pipeline : pipelinesToCheck_)
{
if (!pipeline)
{
// Not good, but let's try not to crash.
continue;
}
if (!pipeline->pipeline[(size_t)rpType])
{
pipeline->pipeline[(size_t)rpType] = Promise<VkPipeline>::CreateEmpty();
_assert_(renderPass);
compileQueue_.push_back(CompileQueueEntry(pipeline,
renderPass->Get(vulkan_, rpType, sampleCount),rpType, sampleCount));
needsCompile = true;
}
}
}
push_back不如emplace_back
省流 setenv/getenv不是线程安全的。涉及到多个语言runtime读写env了。倒霉赶上了属于是
省流,tie
struct Person
{
std::string first_name;
std::string last_name;
std::uint8_t age;
auto tied() const
{
return std::tie(first_name, last_name, age);
}
bool operator==(const Person& other) const
{
return tied() == other.tied();
}
bool operator<(const Person& other) const
{
return tied() < other.tied();
}
};
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线
- https://github.com/msqr1/importizer 帮助转module的工具