Monday, February 12, 2024

Elegant way to create Segfault with C++ and Google Test

Let's say you have a gRPC interface and several domain classes in your app that rely on that interface. Now you want to implement unit tests for the domain classes. The test suits for each class are split into separate cpp file. In every file, a mock class for the gRPC client class is defined. Mocking only required methods seems a good idea.

ClassFloorTests.cpp

class MockBuildingGrpcClient : public BuildingGrpcClient
{
public:
MockBuildingGrpcClient() : BuildingGrpcClient(nullptr){};
MOCK_METHOD(int, GetFloorList, (), (override));
MOCK_METHOD(int, AddFloor, (string& name), (override));
MOCK_METHOD(int, RemoveFloor, (int id), (override));
};

ClassAppartmentTests.cpp

class MockBuildingGrpcClient : public BuildingGrpcClient
{
public:
MockBuildingGrpcClient() : BuildingGrpcClient(nullptr){};
MOCK_METHOD(int, GetAppartmentList, (), (override));
MOCK_METHOD(int, AddAppartment, (string& name), (override));
MOCK_METHOD(int, RemoveAppartment, (int id), (override));
};

The trap is that for linker these 2 constructors for MockBuildingGrpcClient look the same if they are in the same namespace, which is most probably the case. In both cpp files, the same constructor is called, which is not what the C++ user expects. At some point, this background leads to Segfault. Either at the mock class constructor call or when calling one of the gRPC methods. For me, g++ and the newest cppcheck didn't issue any warnings for this code. Thankfully, after I tried to isolate the problem, it didn't take a lot of time to catch it.

todo: If there is some interest in this topic I might consider adding the output from GDB at the point of Segfault.

Wednesday, October 13, 2021

AOSP build debugging. Ninja output

Android AOSP build errors are usually very tricky to debug. AOSP build consists of dozens of makefiles not to mention Blueprint or Android.bp files introduced with Soong. Android put Soong Build System on top of existing makefiles starting from 7.0 release. For input it takes makefiles and .bp files from hundreds of repositories included in AOSP. On output it produces executables, images, build system intermediaries, etc.

When you got build failure at least the following AOSP build logs are available for examination (probably not comprehensive):

  • out/soong.log
  • out/verbose.log.gz/verbose.log

Ninja is on the lower level of build hierarchy. It starts final build commands generated on all previous steps. If build error is related to Ninja there is a bunch of convenient internal tools for investigation.

For example, I got the following error in out/soong.log

build/soong/ui/build/dumpvars.go:109: BOARD_SUPPORTS_EARLY_INIT true
build/soong/ui/build/exec.go:57: build/blueprint/bootstrap.bash [build/blueprint/bootstrap.bash -t]
build/soong/ui/build/exec.go:57: out/soong/.bootstrap/bin/soong_env [out/soong/.bootstrap/bin/soong_env out/soong/.soong.environment]
build/soong/ui/build/exec.go:57: prebuilts/build-tools/linux-x86/bin/ninja [prebuilts/build-tools/linux-x86/bin/ninja -d keepdepfile -w dupbuild=err -j 4 --frontend_file out/.ninja_fifo -f out/soong/.minibootstrap/build.ninja]
build/soong/ui/build/exec.go:57: prebuilts/build-tools/linux-x86/bin/ninja [prebuilts/build-tools/linux-x86/bin/ninja -d keepdepfile -w dupbuild=err -j 4 --frontend_file out/.ninja_fifo -f out/soong/.bootstrap/build.ninja]
build/soong/ui/build/exec.go:95: soong bootstrap failed with: exit status 2


I found a corresponding code in Soong source and passed additional parameters to Ninja.

file: build/soong/ui/build/soong.go at the end of func runSoong()

func runSoong(ctx Context, config Config) {
... 
ninja := func(name, file string) {
ctx.BeginTrace(metrics.RunSoong, name)
defer ctx.EndTrace()

fifo := filepath.Join(config.OutDir(), ".ninja_fifo")
nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
defer nr.Close()

cmd := Command(ctx, config, "soong "+name,
config.PrebuiltBuildTool("ninja"),
"-d", "keepdepfile",
"-w", "dupbuild=err",
"-j", strconv.Itoa(config.Parallel()),
"--frontend_file", fifo,
"-f", filepath.Join(config.SoongOutDir(), file))
cmd.Sandbox = soongSandbox
cmd.RunAndPrintOrFatal()
}

ninja("minibootstrap", ".minibootstrap/build.ninja")
ninja("bootstrap", ".bootstrap/build.ninja")
 
Notice 2 invocations of function ninja() that provides log entries for minibootstrap and bootstrap.

Tuesday, September 21, 2021

Android BSP BUILDTYPE internals: user vs userdebug

Android documentation states that:

The userdebug build should behave the same as the user build, with the ability to enable additional debugging that normally violates the security model of the platform.

Sometimes the actual build behavior is not as expected and we need to check what are the differences between user and userdebug. It starts with the lunch command:

$ lunch aosp_arm-user

The BUILDTYPE flag is saved in the shell environment as $TARGET_BUILD_VARIANT.

I tracked down AOSP source for $TARGET_BUILD_VARIANT.

The diagram shows some of the most interesting occurrences.

1st thing for the further investigation is a difference between 2
KERNEL_DEFCONFIG files.