This commit is contained in:
		
							parent
							
								
									2ffecd9aae
								
							
						
					
					
						commit
						26727a63e0
					
				
					 3 changed files with 195 additions and 201 deletions
				
			
		|  | @ -20,4 +20,4 @@ target_link_libraries(surface PUBLIC | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| add_test_module(surface system.test.cpp) | add_test_module(surface system.test.cpp) | ||||||
| # add_fuzz_module(surface system.fuzz.cpp) | add_fuzz_module(surface system.fuzz.cpp) | ||||||
|  |  | ||||||
|  | @ -85,203 +85,197 @@ private: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Suite raii = "raii"_suite = [] { | Suite raii = "raii"_suite = [] { | ||||||
| 	// should trigger memory sanitizer error
 | 	Case { "happy path won't throw" } = [] { | ||||||
| 	//
 | 		auto fixture = Fixture {}; | ||||||
| 	int x;         // uninitialized
 | 		ignore = System { fixture.registry() }; | ||||||
| 	int y = x + 1; // use of uninitialized value
 | 	}; | ||||||
| 	printf("y = %d\n", y); | 
 | ||||||
|  | 	Case { "many won't freeze/throw" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		for (auto idx : std::views::iota(0, 250)) | ||||||
|  | 		{ | ||||||
|  | 			ignore = System { fixture.registry() }; | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "unhappy path throws" } = [] { | ||||||
|  | 		expect_throw([] { ignore = System { {} }; }); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "post construct has correct state" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "post destruct has correct state" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = memory::create_scope<System>(fixture.registry()); | ||||||
|  | 
 | ||||||
|  | 		fixture.create_component(); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1); | ||||||
|  | 
 | ||||||
|  | 		system.reset(); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0); | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Suite system_events = "system_events"_suite = [] { | ||||||
|  | 	Case { "on_register won't throw" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 
 | ||||||
|  | 		system.on_register(); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "on_unregister won't throw" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 
 | ||||||
|  | 		system.on_register(); | ||||||
|  | 		system.on_unregister(); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0); | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Suite registry_events = "registry_events"_suite = [] { | ||||||
|  | 	Case { "on_construct<SurfaceComponent> initializes component" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 
 | ||||||
|  | 		const auto &component = fixture.create_component(); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1); | ||||||
|  | 		fixture.check_values(*component); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "unhappy on_construct<SurfaceComponent> throws" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 
 | ||||||
|  | 		expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); | ||||||
|  | 
 | ||||||
|  | 		expect_throw([&] { fixture.create_component({ .resolution = { 0, height } }); }); | ||||||
|  | 
 | ||||||
|  | 		expect_throw([&] { | ||||||
|  | 			fixture.create_component( | ||||||
|  | 			    { .title = "", .resolution = { SurfaceComponent::max_dimension + 1, height } } | ||||||
|  | 			); | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 		expect_throw([&] { | ||||||
|  | 			fixture.create_component( | ||||||
|  | 			    { .title = "", .resolution = { width, SurfaceComponent::max_dimension + 1 } } | ||||||
|  | 			); | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 		auto big_str = std::string {}; | ||||||
|  | 		big_str.resize(SurfaceComponent::max_title_length + 1); | ||||||
|  | 		expect_throw([&] { | ||||||
|  | 			fixture.create_component({ .title = big_str, .resolution = { width, height } }); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "unhappy on_construct<SurfaceComponent> removes component" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 
 | ||||||
|  | 		expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = memory::create_scope<System>(fixture.registry()); | ||||||
|  | 
 | ||||||
|  | 		const auto &component = fixture.create_component(); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1); | ||||||
|  | 		fixture.check_values(*component); | ||||||
|  | 
 | ||||||
|  | 		system.reset(); | ||||||
|  | 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0); | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Suite tick = "tick"_suite = [] { | ||||||
|  | 	Case { "ticking on empty registry won't throw" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		System { fixture.registry() }.tick(tick_info()); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Case { "ticking on non-empty registry won't throw" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 
 | ||||||
|  | 		fixture.create_component(); | ||||||
|  | 		system.tick(tick_info()); | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Suite tick_handles_events = "tick_handles_events"_suite = [] { | ||||||
|  | 	Case { "ticking clears previous tick's events" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 		auto &surface = **fixture.create_component(); | ||||||
|  | 
 | ||||||
|  | 		// flush window-creation events
 | ||||||
|  | 		system.tick(tick_info()); | ||||||
|  | 		expect_eq(surface.peek_events().size(), 0); | ||||||
|  | 
 | ||||||
|  | 		surface.push_event(surface::MovedEvent({}, {})); | ||||||
|  | 		expect_eq(surface.peek_events().size(), 1); | ||||||
|  | 
 | ||||||
|  | 		surface.push_event(surface::ButtonPressedEvent({})); | ||||||
|  | 		expect_eq(surface.peek_events().size(), 2); | ||||||
|  | 
 | ||||||
|  | 		system.tick(tick_info()); | ||||||
|  | 		expect_eq(surface.peek_events().size(), 0); | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Suite tick_handles_requests = "tick_handles_requests"_suite = [] { | ||||||
|  | 	Case { "ticking clears requests" } = [] { | ||||||
|  | 		auto fixture = Fixture {}; | ||||||
|  | 		auto system = System { fixture.registry() }; | ||||||
|  | 		auto &surface = **fixture.create_component(); | ||||||
|  | 
 | ||||||
|  | 		constexpr auto title = "ABC"; | ||||||
|  | 		constexpr auto position = math::ivec2 { 50, 50 }; | ||||||
|  | 		constexpr auto resolution = math::uvec2 { 50, 50 }; | ||||||
|  | 
 | ||||||
|  | 		expect_eq(surface.peek_requests().size(), 0); | ||||||
|  | 
 | ||||||
|  | 		surface.push_request(surface::ModifyVisibilityRequest(true)); | ||||||
|  | 		expect_eq(surface.peek_requests().size(), 1); | ||||||
|  | 		system.tick(tick_info()); | ||||||
|  | 		expect_eq(surface.peek_requests().size(), 0); | ||||||
|  | 
 | ||||||
|  | 		surface.push_request(surface::ModifyTitleRequest(title)); | ||||||
|  | 		expect_eq(surface.peek_requests().size(), 1); | ||||||
|  | 
 | ||||||
|  | 		surface.push_request(surface::ModifyResolutionRequest(resolution)); | ||||||
|  | 		surface.push_request(surface::ModifyPositionRequest(position)); | ||||||
|  | 		expect_eq(surface.peek_requests().size(), 1 + 2); | ||||||
|  | 
 | ||||||
|  | 		surface.push_request(surface::ModifyVisibilityRequest(false)); | ||||||
|  | 		surface.push_request(surface::ModifyVisibilityRequest(true)); | ||||||
|  | 		surface.push_request(surface::ModifyVisibilityRequest(false)); | ||||||
|  | 		expect_eq(surface.peek_requests().size(), 1 + 2 + 3); | ||||||
|  | 
 | ||||||
|  | 		system.tick(tick_info()); | ||||||
|  | 		expect_eq(surface.peek_requests().size(), 0); | ||||||
|  | 
 | ||||||
|  | 		expect_eq(surface.get_title(), title); | ||||||
|  | 		expect_eq(surface.get_position(), position); | ||||||
|  | 		expect_eq(surface.get_resolution(), resolution); | ||||||
|  | 
 | ||||||
|  | 		log_dbg("EVENT COUNT: {}", surface.peek_events().size()); | ||||||
|  | 		for (const auto &event : surface.peek_events()) | ||||||
|  | 		{ | ||||||
|  | 			const auto visitor = overloads { | ||||||
|  | 				[&](auto event) { log_dbg("event: {}", event.to_string()); }, | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			std::visit(visitor, event); | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
| }; | }; | ||||||
| // 	Case { "happy path won't throw" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		ignore = System { fixture.registry() };
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "many won't freeze/throw" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		for (auto idx : std::views::iota(0, 250))
 |  | ||||||
| // 		{
 |  | ||||||
| // 			ignore = System { fixture.registry() };
 |  | ||||||
| // 		}
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "unhappy path throws" } = [] {
 |  | ||||||
| // 		expect_throw([] { ignore = System { {} }; });
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "post construct has correct state" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "post destruct has correct state" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = memory::create_scope<System>(fixture.registry());
 |  | ||||||
| //
 |  | ||||||
| // 		fixture.create_component();
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
 |  | ||||||
| //
 |  | ||||||
| // 		system.reset();
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
 |  | ||||||
| // 	};
 |  | ||||||
| // };
 |  | ||||||
| //
 |  | ||||||
| // Suite system_events = "system_events"_suite = [] {
 |  | ||||||
| // 	Case { "on_register won't throw" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| //
 |  | ||||||
| // 		system.on_register();
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "on_unregister won't throw" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| //
 |  | ||||||
| // 		system.on_register();
 |  | ||||||
| // 		system.on_unregister();
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
 |  | ||||||
| // 	};
 |  | ||||||
| // };
 |  | ||||||
| //
 |  | ||||||
| // Suite registry_events = "registry_events"_suite = [] {
 |  | ||||||
| // 	Case { "on_construct<SurfaceComponent> initializes component" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| //
 |  | ||||||
| // 		const auto &component = fixture.create_component();
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
 |  | ||||||
| // 		fixture.check_values(*component);
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "unhappy on_construct<SurfaceComponent> throws" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| //
 |  | ||||||
| // 		expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); });
 |  | ||||||
| //
 |  | ||||||
| // 		expect_throw([&] { fixture.create_component({ .resolution = { 0, height } }); });
 |  | ||||||
| //
 |  | ||||||
| // 		expect_throw([&] {
 |  | ||||||
| // 			fixture.create_component(
 |  | ||||||
| // 			    { .title = "", .resolution = { SurfaceComponent::max_dimension + 1, height } }
 |  | ||||||
| // 			);
 |  | ||||||
| // 		});
 |  | ||||||
| //
 |  | ||||||
| // 		expect_throw([&] {
 |  | ||||||
| // 			fixture.create_component(
 |  | ||||||
| // 			    { .title = "", .resolution = { width, SurfaceComponent::max_dimension + 1 } }
 |  | ||||||
| // 			);
 |  | ||||||
| // 		});
 |  | ||||||
| //
 |  | ||||||
| // 		auto big_str = std::string {};
 |  | ||||||
| // 		big_str.resize(SurfaceComponent::max_title_length + 1);
 |  | ||||||
| // 		expect_throw([&] {
 |  | ||||||
| // 			fixture.create_component({ .title = big_str, .resolution = { width, height } });
 |  | ||||||
| // 		});
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "unhappy on_construct<SurfaceComponent> removes component" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| //
 |  | ||||||
| // 		expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); });
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = memory::create_scope<System>(fixture.registry());
 |  | ||||||
| //
 |  | ||||||
| // 		const auto &component = fixture.create_component();
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
 |  | ||||||
| // 		fixture.check_values(*component);
 |  | ||||||
| //
 |  | ||||||
| // 		system.reset();
 |  | ||||||
| // 		expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
 |  | ||||||
| // 	};
 |  | ||||||
| // };
 |  | ||||||
| //
 |  | ||||||
| // Suite tick = "tick"_suite = [] {
 |  | ||||||
| // 	Case { "ticking on empty registry won't throw" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		System { fixture.registry() }.tick(tick_info());
 |  | ||||||
| // 	};
 |  | ||||||
| //
 |  | ||||||
| // 	Case { "ticking on non-empty registry won't throw" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| //
 |  | ||||||
| // 		fixture.create_component();
 |  | ||||||
| // 		system.tick(tick_info());
 |  | ||||||
| // 	};
 |  | ||||||
| // };
 |  | ||||||
| //
 |  | ||||||
| // Suite tick_handles_events = "tick_handles_events"_suite = [] {
 |  | ||||||
| // 	Case { "ticking clears previous tick's events" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| // 		auto &surface = **fixture.create_component();
 |  | ||||||
| //
 |  | ||||||
| // 		// flush window-creation events
 |  | ||||||
| // 		system.tick(tick_info());
 |  | ||||||
| // 		expect_eq(surface.peek_events().size(), 0);
 |  | ||||||
| //
 |  | ||||||
| // 		surface.push_event(surface::MovedEvent({}, {}));
 |  | ||||||
| // 		expect_eq(surface.peek_events().size(), 1);
 |  | ||||||
| //
 |  | ||||||
| // 		surface.push_event(surface::ButtonPressedEvent({}));
 |  | ||||||
| // 		expect_eq(surface.peek_events().size(), 2);
 |  | ||||||
| //
 |  | ||||||
| // 		system.tick(tick_info());
 |  | ||||||
| // 		expect_eq(surface.peek_events().size(), 0);
 |  | ||||||
| // 	};
 |  | ||||||
| // };
 |  | ||||||
| //
 |  | ||||||
| // Suite tick_handles_requests = "tick_handles_requests"_suite = [] {
 |  | ||||||
| // 	Case { "ticking clears requests" } = [] {
 |  | ||||||
| // 		auto fixture = Fixture {};
 |  | ||||||
| // 		auto system = System { fixture.registry() };
 |  | ||||||
| // 		auto &surface = **fixture.create_component();
 |  | ||||||
| //
 |  | ||||||
| // 		constexpr auto title = "ABC";
 |  | ||||||
| // 		constexpr auto position = math::ivec2 { 50, 50 };
 |  | ||||||
| // 		constexpr auto resolution = math::uvec2 { 50, 50 };
 |  | ||||||
| //
 |  | ||||||
| // 		expect_eq(surface.peek_requests().size(), 0);
 |  | ||||||
| //
 |  | ||||||
| // 		surface.push_request(surface::ModifyVisibilityRequest(true));
 |  | ||||||
| // 		expect_eq(surface.peek_requests().size(), 1);
 |  | ||||||
| // 		system.tick(tick_info());
 |  | ||||||
| // 		expect_eq(surface.peek_requests().size(), 0);
 |  | ||||||
| //
 |  | ||||||
| // 		surface.push_request(surface::ModifyTitleRequest(title));
 |  | ||||||
| // 		expect_eq(surface.peek_requests().size(), 1);
 |  | ||||||
| //
 |  | ||||||
| // 		surface.push_request(surface::ModifyResolutionRequest(resolution));
 |  | ||||||
| // 		surface.push_request(surface::ModifyPositionRequest(position));
 |  | ||||||
| // 		expect_eq(surface.peek_requests().size(), 1 + 2);
 |  | ||||||
| //
 |  | ||||||
| // 		surface.push_request(surface::ModifyVisibilityRequest(false));
 |  | ||||||
| // 		surface.push_request(surface::ModifyVisibilityRequest(true));
 |  | ||||||
| // 		surface.push_request(surface::ModifyVisibilityRequest(false));
 |  | ||||||
| // 		expect_eq(surface.peek_requests().size(), 1 + 2 + 3);
 |  | ||||||
| //
 |  | ||||||
| // 		system.tick(tick_info());
 |  | ||||||
| // 		expect_eq(surface.peek_requests().size(), 0);
 |  | ||||||
| //
 |  | ||||||
| // 		expect_eq(surface.get_title(), title);
 |  | ||||||
| // 		expect_eq(surface.get_position(), position);
 |  | ||||||
| // 		expect_eq(surface.get_resolution(), resolution);
 |  | ||||||
| //
 |  | ||||||
| // 		log_dbg("EVENT COUNT: {}", surface.peek_events().size());
 |  | ||||||
| // 		for (const auto &event : surface.peek_events())
 |  | ||||||
| // 		{
 |  | ||||||
| // 			const auto visitor = overloads {
 |  | ||||||
| // 				[&](auto event) { log_dbg("event: {}", event.to_string()); },
 |  | ||||||
| // 			};
 |  | ||||||
| //
 |  | ||||||
| // 			std::visit(visitor, event);
 |  | ||||||
| // 		}
 |  | ||||||
| // 	};
 |  | ||||||
| // };
 |  | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ cmake . \ | ||||||
| -L/libcxx_msan/lib -Wl,-rpath,/libcxx_msan/lib \ | -L/libcxx_msan/lib -Wl,-rpath,/libcxx_msan/lib \ | ||||||
| -lc++ \ | -lc++ \ | ||||||
| -lc++abi" \ | -lc++abi" \ | ||||||
| && cmake --build ./build --target='surface_tests' -j`nproc` | && cmake --build ./build -j`nproc` | ||||||
| 
 | 
 | ||||||
| export MSAN_SYMBOLIZER_PATH="$(which llvm-symbolizer)" | export MSAN_SYMBOLIZER_PATH="$(which llvm-symbolizer)" | ||||||
| export MSAN_OPTIONS="fast_unwind_on_malloc=0:verbosity=1:report_umrs=1" | export MSAN_OPTIONS="fast_unwind_on_malloc=0:verbosity=1:report_umrs=1" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue