/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * 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.
 */

// To access constructor of CursorWindow along with its fields
#define private public

#include <androidfw/CursorWindow.h>
#include <binder/Parcel.h>
#include <utils/String8.h>
#include "../includes/common.h"
#include "../includes/memutils_track.h"

using namespace android;

char enable_selective_overload = ENABLE_NONE;
bool is_tracking_required(size_t size) {
    return (size != 0);
}
constexpr int kSize = 0;
String8 kEmptyString = String8("");

int main() {
    // Create CursorWindow object to invoke CursorWindow::create() to get the CursorWindow class's
    // constructor
    CursorWindow* window;
    CursorWindow::create(kEmptyString, kSize, &window);

    // Create parcel object
    Parcel parcelObj;
    Parcel* parcel = &parcelObj;

    // Assign values to window object to hit the vulnerability from CursorWindow.h
    window->mAllocOffset = 1;
    window->mName = kEmptyString;
    window->mNumColumns = kSize;
    window->mNumRows = kSize;
    window->mSize = kSize;
    window->mSlotsOffset = kSize;

    // Invoke vulnerable function
    enable_selective_overload = ENABLE_MALLOC_CHECK;
    window->writeToParcel(parcel);
    enable_selective_overload = ENABLE_NONE;

    // Set data position of parcel to 0
    parcel->setDataPosition(0);

    // Since writes were made on parcel object in source code, hence the exact same reads have to
    // be made and checked accordingly to access the correct index of parcel
    FAIL_CHECK(parcel->readString8().string() == kEmptyString);
    FAIL_CHECK(parcel->readUint32(&window->mNumRows) == kSize);
    FAIL_CHECK(parcel->readUint32(&window->mNumColumns) == kSize);
    size_t compactSize = parcel->readUint32(); /* value is different with and without fix */
    parcel->readBool();

    // Create pointer dest using compactSize
    const void* dest = parcel->readInplace(compactSize);
    FAIL_CHECK(dest);

    const uint8_t* leakedBytes = static_cast<const uint8_t*>(dest) + compactSize;
    FAIL_CHECK(leakedBytes);

    // Check if any leaks are present in leakedBytes
    // The fix removes the code that CursorWindow::writeToParcel() uses to ensure slot data is
    // 4-byte aligned because 'mAllocOffset' and 'mSlotsOffset' are already 4-byte aligned,
    // alignment step here is unnecessary which causes leak of uninitialized heap content
    // INITIAL_VAL = 0xBE
    bool isVulnerable = false;
    if (leakedBytes[0] == INITIAL_VAL && leakedBytes[1] == INITIAL_VAL &&
        leakedBytes[2] == INITIAL_VAL) {
        isVulnerable = true;
    }

    return isVulnerable ? EXIT_VULNERABLE : EXIT_SUCCESS;
}