Skip to content

Commit

Permalink
[midi1/2] Catch trying to convert invalid midi 1 bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Oct 26, 2024
1 parent 6245d5b commit 952f781
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 16 deletions.
4 changes: 4 additions & 0 deletions cmake/libremidi.tests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ if(LIBREMIDI_CI)
target_compile_definitions(libremidi ${_public} LIBREMIDI_CI)
endif()

add_executable(conversion_test tests/unit/conversion.cpp)
target_link_libraries(conversion_test PRIVATE libremidi Catch2::Catch2WithMain)

add_executable(error_test tests/unit/error.cpp)
target_link_libraries(error_test PRIVATE libremidi Catch2::Catch2WithMain)

Expand All @@ -36,6 +39,7 @@ add_executable(midifile_write_tracks_test tests/integration/midifile_write_track
target_link_libraries(midifile_write_tracks_test PRIVATE libremidi Catch2::Catch2WithMain)

include(CTest)
add_test(NAME conversion_test COMMAND conversion_test)
add_test(NAME error_test COMMAND error_test)
add_test(NAME midiin_test COMMAND midiin_test --allow-running-no-tests)
add_test(NAME midiout_test COMMAND midiout_test --allow-running-no-tests)
Expand Down
2 changes: 1 addition & 1 deletion examples/sysextest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ int main(int argc, const char** argv)
{
message.clear();
message.push_back(240);
for (auto i = 0U; i < args.count; i++)
for (int i = 0; i < args.count; i++)
message.push_back(i % 128);

message.push_back(247);
Expand Down
2 changes: 1 addition & 1 deletion examples/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ struct arguments
return false;
}

if (index >= 0 && index < ports.size())
if (index >= 0 && index < std::ssize(ports))
{
std::cout << "Opening " << ports[index].display_name << std::endl;
const auto err = midi.open_port(ports[index]);
Expand Down
7 changes: 6 additions & 1 deletion include/libremidi/cmidi2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2559,6 +2559,7 @@ enum cmidi2_midi_conversion_result
CMIDI2_CONVERSION_RESULT_INVALID_DTE_SEQUENCE = 0x11,
CMIDI2_CONVERSION_RESULT_INVALID_STATUS = 0x13,
CMIDI2_CONVERSION_RESULT_INCOMPLETE_SYSEX7 = 0x20,
CMIDI2_CONVERSION_RESULT_INVALID_INPUT = 0x40,
};

static inline void
Expand Down Expand Up @@ -2686,7 +2687,11 @@ cmidi2_convert_midi1_to_ump(cmidi2_midi_conversion_context* context)
else
{
// fixed sized message
size_t len = cmidi2_midi1_get_message_size(context->midi1 + *sIdx, sLen - *sIdx);
size_t remaining = sLen - *sIdx;
size_t len = cmidi2_midi1_get_message_size(context->midi1 + *sIdx, remaining);
if (len > remaining)
return CMIDI2_CONVERSION_RESULT_INVALID_INPUT;

uint8_t byte2 = context->midi1[*sIdx + 1];
uint8_t byte3 = len > 2 ? context->midi1[*sIdx + 2] : 0;
uint8_t channel = context->midi1[*sIdx] & 0xF;
Expand Down
13 changes: 6 additions & 7 deletions include/libremidi/detail/conversion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ struct midi1_to_midi2
stdx::error
convert(const unsigned char* message, std::size_t size, int64_t timestamp, auto on_ump)
{
uint32_t ump[65536 / 4];

context.midi1 = const_cast<unsigned char*>(message);
context.midi1_num_bytes = size;
context.midi1_proceeded_bytes = 0;
Expand All @@ -26,23 +24,23 @@ struct midi1_to_midi2
if (auto res = cmidi2_convert_midi1_to_ump(&context); res != CMIDI2_CONVERSION_RESULT_OK)
return std::errc::invalid_argument;

on_ump(context.ump, context.ump_proceeded_bytes / 4, timestamp);
return stdx::error{};
return on_ump(context.ump, context.ump_proceeded_bytes / 4, timestamp);
}

cmidi2_midi_conversion_context context = [] {
cmidi2_midi_conversion_context tmp;
cmidi2_midi_conversion_context_initialize(&tmp);
return tmp;
}();
uint32_t ump[65536 / 4];
};

struct midi2_to_midi1
{
stdx::error convert(const uint32_t* message, std::size_t size, int64_t timestamp, auto on_midi)
stdx::error
convert(const uint32_t* message, std::size_t /* size */, int64_t timestamp, auto on_midi)
{
uint8_t midi[65536];
const auto n
auto n
= cmidi2_convert_single_ump_to_midi1(midi, sizeof(midi), const_cast<uint32_t*>(message));
if (n > 0)
return on_midi(midi, n, timestamp);
Expand All @@ -55,6 +53,7 @@ struct midi2_to_midi1
cmidi2_midi_conversion_context_initialize(&tmp);
return tmp;
}();
uint8_t midi[65536];
};

}
6 changes: 0 additions & 6 deletions include/libremidi/libremidi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,6 @@ class LIBREMIDI_EXPORT midi_out
stdx::error send_message(unsigned char b0, unsigned char b1, unsigned char b2) const;

// Avoid silly mistakes:
stdx::error send_message(int16_t b0) const noexcept = delete;
stdx::error send_message(int32_t b0) const noexcept = delete;
stdx::error send_message(int64_t b0) const noexcept = delete;
stdx::error send_message(uint16_t b0) const noexcept = delete;
stdx::error send_message(uint32_t b0) const noexcept = delete;
stdx::error send_message(uint64_t b0) const noexcept = delete;
stdx::error send_message(auto* message) const noexcept = delete;
stdx::error send_message(const auto* message) const noexcept = delete;

Expand Down
105 changes: 105 additions & 0 deletions tests/unit/conversion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "../include_catch.hpp"

#include <libremidi/detail/conversion.hpp>
#include <libremidi/libremidi.hpp>

#include <array>
#include <bit>

TEST_CASE("convert midi1 to midi2", "[midi_in]")
{
libremidi::midi1_to_midi2 m1;
GIVEN("Correct input")
{
bool ok = false;
auto msg = libremidi::channel_events::control_change(3, 35, 100);

std::vector<uint32_t> res;
auto err
= m1.convert(msg.bytes.data(), msg.size(), 0, [&](uint32_t* ump, std::size_t sz, int64_t) {
ok = true;
res.assign(ump, ump + sz);
return stdx::error{};
});

THEN("Correct conversion")
{
REQUIRE(err == stdx::error{});
REQUIRE(ok);
auto expected = cmidi2_ump_midi2_cc(0, 2, 35, 100 << 25);
union
{
uint32_t u[2];
int64_t i;
} e{.i = expected};

REQUIRE(res.size() == 2);
REQUIRE(e.u[1] == res[0]);
REQUIRE(e.u[0] == res[1]);
}
}

GIVEN("Wrong input")
{
bool ok = false;
unsigned char arr[1]{156};
auto err = m1.convert(arr, 1, 0, [&](uint32_t*, std::size_t, int64_t) {
ok = true;
return stdx::error{};
});
THEN("We get an error")
{
REQUIRE(err != stdx::error{});
REQUIRE(ok == false);
}
}
}

TEST_CASE("convert midi2 to midi1", "[midi_in]")
{
libremidi::midi2_to_midi1 m1;
GIVEN("Correct input")
{
bool ok = false;
auto msg = cmidi2_ump_midi2_cc(0, 2, 35, 100 << 25);
union
{
uint32_t u[2];
int64_t i;
} e{.i = msg};
using namespace std;
swap(e.u[0], e.u[1]);

std::vector<uint8_t> res;
auto err = m1.convert(e.u, 2, 0, [&](uint8_t* midi, std::size_t sz, int64_t) {
ok = true;
res.assign(midi, midi + sz);
return stdx::error{};
});

THEN("Correct conversion")
{
REQUIRE(err == stdx::error{});
REQUIRE(ok);
auto msg = libremidi::channel_events::control_change(3, 35, 100);

REQUIRE(res.size() == 3);
REQUIRE(res == std::vector<uint8_t>(msg.begin(), msg.end()));
}
}

GIVEN("Wrong input")
{
bool ok = false;
uint32_t res = 0xFFFFFFFF;
auto err = m1.convert(&res, 1, 0, [&](uint8_t*, std::size_t, int64_t) {
ok = true;
return stdx::error{};
});
THEN("We get an error")
{
REQUIRE(err != stdx::error{});
REQUIRE(ok == false);
}
}
}

0 comments on commit 952f781

Please sign in to comment.