Skip to content

Latest commit

 

History

History
396 lines (307 loc) · 8.39 KB

177.md

File metadata and controls

396 lines (307 loc) · 8.39 KB
layout title
post
第177期

C++ 中文周刊 2025-02-01 第177期

周刊项目地址

公众号

点击「查看原文」跳转到 GitHub 上对应文件,链接就可以点击了

qq群 点击进入 满了加这个 729240657

RSS

欢迎投稿,推荐或自荐文章/软件/资源等,评论区留言

本期文章由 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();
    }
};

开源项目介绍


上一期 下一期