[darwin-framework-tool] Automatically check for leaks on shutdown if enable_leak_checking is true (#35936)

diff --git a/examples/darwin-framework-tool/BUILD.gn b/examples/darwin-framework-tool/BUILD.gn
index 665dccf..2c20247 100644
--- a/examples/darwin-framework-tool/BUILD.gn
+++ b/examples/darwin-framework-tool/BUILD.gn
@@ -43,6 +43,9 @@
 
   # Disable generating compiler database by default
   generate_compilation_database = false
+
+  # Enable automatic leak checks before the application exits
+  enable_leak_checking = false
 }
 
 sdk = "macosx"
@@ -219,6 +222,7 @@
     "commands/provider/OTASoftwareUpdateInteractive.mm",
     "commands/storage/Commands.h",
     "commands/storage/StorageManagementCommand.mm",
+    "debug/LeakChecker.mm",
     "logging/logging.mm",
     "main.mm",
   ]
@@ -280,6 +284,10 @@
     defines += [ "MTR_ENABLE_PROVISIONAL=1" ]
   }
 
+  if (enable_leak_checking) {
+    defines += [ "DFT_ENABLE_LEAK_CHECKING=1" ]
+  }
+
   public_configs = [ ":config" ]
 
   output_dir = root_out_dir
diff --git a/examples/darwin-framework-tool/debug/LeakChecker.h b/examples/darwin-framework-tool/debug/LeakChecker.h
new file mode 100644
index 0000000..c83ed64
--- /dev/null
+++ b/examples/darwin-framework-tool/debug/LeakChecker.h
@@ -0,0 +1,28 @@
+/*
+ *   Copyright (c) 2024 Project CHIP Authors
+ *   All rights reserved.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+#pragma once
+
+/*
+ * This function performs a memory leak check if the build flag `enable_leak_checking` is set to true
+ * If leaks are detected, it overrides the provided exit code with `EXIT_FAILURE`.
+ *
+ * @param exitCode The initial exit code to return if no leaks are detected or if leak checking is disabled.
+ * @return `EXIT_FAILURE` if leaks are detected and leak checking is enabled; otherwise, the original `exitCode`.
+ */
+int ConditionalLeaksCheck(int exitCode);
diff --git a/examples/darwin-framework-tool/debug/LeakChecker.mm b/examples/darwin-framework-tool/debug/LeakChecker.mm
new file mode 100644
index 0000000..72a4414
--- /dev/null
+++ b/examples/darwin-framework-tool/debug/LeakChecker.mm
@@ -0,0 +1,70 @@
+/*
+ *   Copyright (c) 2024 Project CHIP Authors
+ *   All rights reserved.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+#include "LeakChecker.h"
+
+#import <Foundation/Foundation.h>
+#include <unistd.h> // For getpid()
+
+@interface LeakChecker : NSObject
+- (BOOL)hasMemoryLeaks;
+@end
+
+@implementation LeakChecker
+
+- (BOOL)hasMemoryLeaks
+{
+    pid_t pid = getpid();
+    auto * pidString = [NSString stringWithFormat:@"%d", pid];
+
+    auto * task = [[NSTask alloc] init];
+    task.launchPath = @"/usr/bin/leaks";
+    task.arguments = @[ pidString ];
+
+    auto * pipe = [NSPipe pipe];
+    task.standardOutput = pipe;
+    task.standardError = pipe;
+
+    NSFileHandle * fileHandle = [pipe fileHandleForReading];
+    [task launch];
+    [task waitUntilExit];
+
+    int exitCode = [task terminationStatus];
+    if (exitCode) {
+        NSData * data = [fileHandle readDataToEndOfFile];
+        NSString * output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSLog(@"%@", output);
+        return YES;
+    }
+
+    return NO;
+}
+
+@end
+
+int ConditionalLeaksCheck(int exitCode)
+{
+#ifdef DFT_ENABLE_LEAK_CHECKING
+    auto * leakChecker = [[LeakChecker alloc] init];
+    if ([leakChecker hasMemoryLeaks]) {
+        return EXIT_FAILURE;
+    }
+#endif // DFT_ENABLE_LEAK_CHECKING
+
+    return exitCode;
+}
diff --git a/examples/darwin-framework-tool/main.mm b/examples/darwin-framework-tool/main.mm
index 5f31cb6..ad31cfe 100644
--- a/examples/darwin-framework-tool/main.mm
+++ b/examples/darwin-framework-tool/main.mm
@@ -18,6 +18,7 @@
 
 #import <Matter/Matter.h>
 
+#import "debug/LeakChecker.h"
 #import "logging/logging.h"
 
 #include "commands/bdx/Commands.h"
@@ -35,6 +36,7 @@
 
 int main(int argc, const char * argv[])
 {
+    int exitCode = EXIT_SUCCESS;
     @autoreleasepool {
         dft::logging::Setup();
 
@@ -49,6 +51,7 @@
         registerCommandsStorage(commands);
         registerCommandsConfiguration(commands);
         registerClusters(commands);
-        return commands.Run(argc, (char **) argv);
+        exitCode = commands.Run(argc, (char **) argv);
     }
+    return ConditionalLeaksCheck(exitCode);
 }
diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
index afc1df1..8a39c63 100644
--- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
+++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
@@ -373,6 +373,8 @@
 		B4E262172AA0CF2000DBA5BC /* RemoteDataModelLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = B4E262132AA0C7A300DBA5BC /* RemoteDataModelLogger.h */; };
 		B4E2621B2AA0D02000DBA5BC /* SleepCommand.mm in Sources */ = {isa = PBXBuildFile; fileRef = B4E262192AA0D01D00DBA5BC /* SleepCommand.mm */; };
 		B4E2621E2AA0D02D00DBA5BC /* WaitForCommissioneeCommand.mm in Sources */ = {isa = PBXBuildFile; fileRef = B4E2621C2AA0D02A00DBA5BC /* WaitForCommissioneeCommand.mm */; };
+		B4F773CA2CB54B61008C6B23 /* LeakChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = B4F773C72CB54B61008C6B23 /* LeakChecker.h */; };
+		B4F773CB2CB54B61008C6B23 /* LeakChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = B4F773C82CB54B61008C6B23 /* LeakChecker.mm */; };
 		B4FCD56A2B5EDBD300832859 /* MTRDiagnosticLogsType.h in Headers */ = {isa = PBXBuildFile; fileRef = B4FCD5692B5EDBD300832859 /* MTRDiagnosticLogsType.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		B4FCD5702B603A6300832859 /* Commands.h in Headers */ = {isa = PBXBuildFile; fileRef = B4FCD56D2B603A6300832859 /* Commands.h */; };
 		B4FCD5712B603A6300832859 /* DownloadLogCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = B4FCD56E2B603A6300832859 /* DownloadLogCommand.h */; };
@@ -818,6 +820,8 @@
 		B4E262132AA0C7A300DBA5BC /* RemoteDataModelLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteDataModelLogger.h; sourceTree = "<group>"; };
 		B4E262192AA0D01D00DBA5BC /* SleepCommand.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SleepCommand.mm; sourceTree = "<group>"; };
 		B4E2621C2AA0D02A00DBA5BC /* WaitForCommissioneeCommand.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WaitForCommissioneeCommand.mm; sourceTree = "<group>"; };
+		B4F773C72CB54B61008C6B23 /* LeakChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeakChecker.h; sourceTree = "<group>"; };
+		B4F773C82CB54B61008C6B23 /* LeakChecker.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LeakChecker.mm; sourceTree = "<group>"; };
 		B4FCD5692B5EDBD300832859 /* MTRDiagnosticLogsType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDiagnosticLogsType.h; sourceTree = "<group>"; };
 		B4FCD56D2B603A6300832859 /* Commands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Commands.h; sourceTree = "<group>"; };
 		B4FCD56E2B603A6300832859 /* DownloadLogCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DownloadLogCommand.h; sourceTree = "<group>"; };
@@ -874,6 +878,7 @@
 		037C3CA82991A44B00B7EEE2 /* darwin-framework-tool */ = {
 			isa = PBXGroup;
 			children = (
+				B4F773C92CB54B61008C6B23 /* debug */,
 				039145E02993102B00257B3E /* main.mm */,
 				03F430A52994100000166449 /* controller */,
 				039547092992DB02006D42A8 /* editline */,
@@ -1543,6 +1548,15 @@
 			path = delay;
 			sourceTree = "<group>";
 		};
+		B4F773C92CB54B61008C6B23 /* debug */ = {
+			isa = PBXGroup;
+			children = (
+				B4F773C72CB54B61008C6B23 /* LeakChecker.h */,
+				B4F773C82CB54B61008C6B23 /* LeakChecker.mm */,
+			);
+			path = debug;
+			sourceTree = "<group>";
+		};
 		B4FCD56C2B603A6300832859 /* bdx */ = {
 			isa = PBXGroup;
 			children = (
@@ -1594,6 +1608,7 @@
 				037C3DAF2991BD4F00B7EEE2 /* DeviceControllerDelegateBridge.h in Headers */,
 				B4FCD5712B603A6300832859 /* DownloadLogCommand.h in Headers */,
 				037C3DC32991BD5100B7EEE2 /* Commands.h in Headers */,
+				B4F773CA2CB54B61008C6B23 /* LeakChecker.h in Headers */,
 				037C3DB82991BD5000B7EEE2 /* ClusterCommandBridge.h in Headers */,
 				037C3DC82991BD5100B7EEE2 /* CHIPToolKeypair.h in Headers */,
 				037C3DB52991BD5000B7EEE2 /* WriteAttributeCommandBridge.h in Headers */,
@@ -1900,6 +1915,7 @@
 				03F430A82994112B00166449 /* editline.c in Sources */,
 				03F430AA2994113500166449 /* sysunix.c in Sources */,
 				B45373BF2A9FEA9100807602 /* adopt.c in Sources */,
+				B4F773CB2CB54B61008C6B23 /* LeakChecker.mm in Sources */,
 				B45373D12A9FEB0C00807602 /* alloc.c in Sources */,
 				B45373DD2A9FEB5300807602 /* base64-decode.c in Sources */,
 				B45373D22A9FEB0C00807602 /* buflist.c in Sources */,