11// Copyright 2024 syzkaller project authors. All rights reserved.
22// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
33
4+ #include < cstring>
45#include < fcntl.h>
56#include < signal.h>
67#include < sys/mman.h>
1718#include < utility>
1819#include < vector>
1920
21+ #include " pkg/flatrpc/flatrpc.h"
22+
2023inline std::ostream& operator <<(std::ostream& ss, const rpc::ExecRequestRawT& req)
2124{
2225 return ss << " id=" << req.id
@@ -197,7 +200,6 @@ class Proc
197200 return ;
198201 }
199202
200- private:
201203 enum State : uint8 {
202204 // The process has just started.
203205 Started,
@@ -209,6 +211,12 @@ class Proc
209211 Executing,
210212 };
211213
214+ State GetState () const
215+ {
216+ return state_;
217+ }
218+
219+ private:
212220 Connection& conn_;
213221 const char * const bin_;
214222 ProcIDPool& proc_id_pool_;
@@ -575,6 +583,8 @@ class Runner
575583 std::vector<std::string> leak_frames_;
576584 int restarting_ = 0 ;
577585 bool corpus_triaged_ = false ;
586+ bool is_leak_enabled_ = false ;
587+ uint64 exec_count_ = 0 ;
578588 ProcOpts proc_opts_{};
579589
580590 friend std::ostream& operator <<(std::ostream& ss, const Runner& runner)
@@ -621,11 +631,35 @@ class Runner
621631 failmsg (" unknown host message type" , " type=%d" , static_cast <int >(raw.msg .type ));
622632 }
623633
634+ #if GOOS_linux
635+ const uint64 kRunLeakCheckEvery = 2 * procs_.size ();
636+ constexpr auto IsProcIdle = [](const std::unique_ptr<Proc>& proc) {
637+ return proc->GetState () == Proc::State::Idle;
638+ };
639+ const bool isScheduledForLeakCheck =
640+ is_leak_enabled_ &&
641+ corpus_triaged_ &&
642+ exec_count_ > 0 &&
643+ exec_count_ % kRunLeakCheckEvery == 0 ;
644+
645+ if (isScheduledForLeakCheck && std::all_of (procs_.begin (), procs_.end (), IsProcIdle)) {
646+ const int len = leak_frames_.size ();
647+ auto leakFrames = GetArrOfCStr (leak_frames_);
648+ check_leaks (leakFrames, len);
649+ FreeArrOfCStr (leakFrames, len);
650+ ++exec_count_;
651+ }
652+ #else
653+ constexpr bool isScheduledForLeakCheck = false ;
654+ #endif
655+
624656 for (auto & proc : procs_) {
625657 proc->Ready (select, now, requests_.empty ());
626- if (!requests_.empty ()) {
627- if (proc->Execute (requests_.front ()))
658+ if (!isScheduledForLeakCheck && ! requests_.empty ()) {
659+ if (proc->Execute (requests_.front ())) {
628660 requests_.pop_front ();
661+ ++exec_count_;
662+ }
629663 }
630664 }
631665
@@ -667,6 +701,7 @@ class Runner
667701 conn_reply.slowdown , conn_reply.syscall_timeout_ms ,
668702 conn_reply.program_timeout_ms , static_cast <uint64>(conn_reply.features ));
669703 leak_frames_ = conn_reply.leak_frames ;
704+ is_leak_enabled_ = static_cast <bool >(conn_reply.features & rpc::Feature::Leak);
670705
671706 proc_opts_.use_cover_edges = conn_reply.cover_edges ;
672707 proc_opts_.is_kernel_64_bit = is_kernel_64_bit = conn_reply.kernel_64_bit ;
@@ -857,6 +892,27 @@ class Runner
857892
858893 return {status == kFailStatus ? " process failed" : " " , std::move (output)};
859894 }
895+
896+ #if GOOS_linux
897+ char ** GetArrOfCStr (const std::vector<std::string>& vec)
898+ {
899+ char ** arr = new char *[vec.size ()];
900+ std::transform (vec.cbegin (), vec.cend (), arr, [](const std::string& str) {
901+ char * c_str = new char [str.size () + 1 ];
902+ memcpy (c_str, str.c_str (), str.size () + 1 );
903+ return c_str;
904+ });
905+ return arr;
906+ }
907+
908+ void FreeArrOfCStr (char **& arr, int len)
909+ {
910+ for (int i = 0 ; i < len; ++i)
911+ delete[] arr[i];
912+
913+ delete[] arr;
914+ }
915+ #endif
860916};
861917
862918static void SigintHandler (int sig)
0 commit comments