// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "rust-extern-crate.h" #include "rust-diagnostics.h" #include "rust-export-metadata.h" #include "md5.h" namespace Rust { namespace Imports { ExternCrate::ExternCrate (Import::Stream &stream) : import_stream (stream) {} ExternCrate::~ExternCrate () {} bool ExternCrate::ok () const { return !import_stream.saw_error (); } bool ExternCrate::load (Location locus) { // match header import_stream.require_bytes (locus, Metadata::kMagicHeader, sizeof (Metadata::kMagicHeader)); if (import_stream.saw_error ()) return false; // parse 16 bytes md5 unsigned char checksum[16]; bool ok = import_stream.do_peek (sizeof (checksum), (const char **) &checksum); if (!ok) return false; import_stream.advance (sizeof (checksum)); // parse delim import_stream.require_bytes (locus, Metadata::kSzDelim, sizeof (Metadata::kSzDelim)); if (import_stream.saw_error ()) return false; // parse crate name bool saw_delim = false; while (!import_stream.saw_error () && !import_stream.at_eof ()) { unsigned char byte = import_stream.get_char (); saw_delim = memcmp (&byte, Metadata::kSzDelim, sizeof (Metadata::kSzDelim)) == 0; if (saw_delim) break; crate_name += byte; } if (!saw_delim || crate_name.empty ()) { import_stream.set_saw_error (); rust_error_at (locus, "failed to read crate name field"); return false; } // read until delim which is the size of the meta data std::string metadata_length_buffer; saw_delim = false; while (!import_stream.saw_error () && !import_stream.at_eof ()) { unsigned char byte = import_stream.get_char (); saw_delim = memcmp (&byte, Metadata::kSzDelim, sizeof (Metadata::kSzDelim)) == 0; if (saw_delim) break; metadata_length_buffer += byte; } if (!saw_delim || metadata_length_buffer.empty ()) { import_stream.set_saw_error (); rust_error_at (locus, "failed to read metatadata size"); return false; } // interpret the string size int expected_buffer_length = -1; ok = ExternCrate::string_to_int (locus, metadata_length_buffer, false, &expected_buffer_length); if (!ok) return false; // read the parsed size and it should be eof metadata_buffer.reserve (expected_buffer_length); for (int i = 0; i < expected_buffer_length && !import_stream.saw_error () && !import_stream.at_eof (); i++) { metadata_buffer += import_stream.get_char (); } // compute the md5 struct md5_ctx chksm; unsigned char computed_checksum[16]; md5_init_ctx (&chksm); md5_process_bytes (metadata_buffer.c_str (), metadata_buffer.size (), &chksm); md5_finish_ctx (&chksm, computed_checksum); // FIXME i think the encoding and decoding of md5 is going wrong or else we // are not computing it correctly // // compare the checksums // if (memcmp(computed_checksum, checksum, sizeof (checksum)) != 0) // { // rust_error_at (locus, // "checksum mismatch in metadata: %<%.*s%> vs %<%.*s%>", // sizeof (computed_checksum), computed_checksum, // sizeof (checksum), checksum); // return false; // } // all good return true; } const std::string & ExternCrate::get_crate_name () const { return crate_name; } const std::string & ExternCrate::get_metadata () const { return metadata_buffer; } // Turn a string into a integer with appropriate error handling. bool ExternCrate::string_to_int (Location locus, const std::string &s, bool is_neg_ok, int *ret) { char *end; long prio = strtol (s.c_str (), &end, 10); if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok)) { rust_error_at (locus, "invalid integer in import data"); return false; } *ret = prio; return true; } } // namespace Imports } // namespace Rust