/*
 * 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.
 */

#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 = 100; // should be large enough to trigger compaction
                           // logic.
constexpr int kRows = 1;
constexpr int kCols = 1;

String8 kEmptyString = String8("");
/**
 * This test sets up various one-column, one-row CursorWindow objects, each of
 * which contain a single string. This results in a memory layout of:
 * [string data][padding][slot data].
 *
 * The string data and padding are both aligned on word boundaries.
 *
 * Each CursorWindow is written to a Parcel and then the data is read from the
 * Parcel. Then the data is scanned to search for the magic malloc value that
 * indicates a vulnerability.
 */
int main() {
    // Use different length strings to vary the amount of padding between the
    // string data and the slot data.
    for (int i = 0; i <= 5; i++) {
        CursorWindow* rawWindow;
        CursorWindow::create(kEmptyString, kSize, &rawWindow);
        std::unique_ptr<CursorWindow> window(rawWindow); // takes ownership of
                                                         // rawWindow.
        window->setNumColumns(kCols);
        window->allocRow();
        std::string str(i, '\xff');
        window->putString(0, 0, str.data(), i + 1);

        Parcel parcel;

        // Causes all malloc'd bytes to have value 0xBE (INITIAL_VAL in
        // memutils_track.h).
        enable_selective_overload = ENABLE_MALLOC_CHECK;
        window->writeToParcel(&parcel);
        enable_selective_overload = ENABLE_NONE;

        parcel.setDataPosition(0);

        // Read the data from the Parcel.
        FAIL_CHECK(parcel.readString8() == kEmptyString);
        FAIL_CHECK(parcel.readUint32() == kRows); // one row
        FAIL_CHECK(parcel.readUint32() == kCols); // one col
        size_t compactSize = parcel.readUint32();
        parcel.readBool();

        // Read the serialized CursorWindow data.
        const void* dest = parcel.readInplace(compactSize);
        FAIL_CHECK(dest);

        bool isVulnerable = (memchr(dest, INITIAL_VAL, compactSize) != nullptr);
        if (isVulnerable) {
            return EXIT_VULNERABLE;
        }
    }
    return EXIT_SUCCESS;
}
