Repository: dotnet/runtime
File: src/coreclr/vm/hostinformation.cpp (C++)

Code before:

#include "common.h"
#include "hostinformation.h"

namespace
{
    host_runtime_contract s_hostContract = {};
}

void HostInformation::SetContract(_In_ host_runtime_contract* hostContract)
{
    _ASSERTE(s_hostContract.size == 0 && hostContract != nullptr);

    // Copy the contract values
    s_hostContract = *hostContract;
}

bool HostInformation::GetProperty(_In_z_ const char* name, SString& value)
{
    if (s_hostContract.get_runtime_property == nullptr)
        return false;

    size_t len = MAX_PATH + 1;
    char* dest = value.OpenUTF8Buffer(static_cast<COUNT_T>(len) - 1); // OpenUTF8Buffer already includes a byte for the null terminator
    size_t lenActual = s_hostContract.get_runtime_property(name, dest, len, s_hostContract.context);

    // Doesn't exist or failed to get property
    if (lenActual == (size_t)-1 || lenActual == 0)
    {
        value.CloseBuffer(0);
        return false;
    }

    if (lenActual <= len)
    {
        value.CloseBuffer(static_cast<COUNT_T>(lenActual) - 1);
        return true;
    }

    value.CloseBuffer();

    // Buffer was not large enough
    len = lenActual;
    dest = value.OpenUTF8Buffer(static_cast<COUNT_T>(len) - 1); // OpenUTF8Buffer already includes a byte for the null terminator
    lenActual = s_hostContract.get_runtime_property(name, dest, len, s_hostContract.context);

    if (lenActual == (size_t)-1 || lenActual == 0 || lenActual > len)
    {
        value.CloseBuffer(0);
        return false;
    }

Review comment (suggestion):
It might be helpful to command on if `lenActual` includes a null terminator or not.

Code after:

#include "common.h"
#include "hostinformation.h"

namespace
{
    host_runtime_contract s_hostContract = {};
}

void HostInformation::SetContract(_In_ host_runtime_contract* hostContract)
{
    _ASSERTE(s_hostContract.size == 0 && hostContract != nullptr);

    // Copy the contract values
    s_hostContract = *hostContract;
}

bool HostInformation::GetProperty(_In_z_ const char* name, SString& value)
{
    if (s_hostContract.get_runtime_property == nullptr)
        return false;

    size_t len = MAX_PATH + 1;
    char* dest = value.OpenUTF8Buffer(static_cast<COUNT_T>(len) - 1); // OpenUTF8Buffer already includes a byte for the null terminator
    // get_runtime_property returns the length including a null terminator
    size_t lenActual = s_hostContract.get_runtime_property(name, dest, len, s_hostContract.context);

    // Doesn't exist or failed to get property
    if (lenActual == (size_t)-1 || lenActual == 0)
    {
        value.CloseBuffer(0);
        return false;
    }

    if (lenActual <= len)
    {
        value.CloseBuffer(static_cast<COUNT_T>(lenActual) - 1);
        return true;
    }

    value.CloseBuffer();

    // Buffer was not large enough
    len = lenActual;
    dest = value.OpenUTF8Buffer(static_cast<COUNT_T>(len) - 1); // OpenUTF8Buffer already includes a byte for the null terminator
    lenActual = s_hostContract.get_runtime_property(name, dest, len, s_hostContract.context);

    if (lenActual == (size_t)-1 || lenActual == 0 || lenActual > len)
    {
        value.CloseBuffer(0);
        return false;