Merge branch 'master' into master

This commit is contained in:
Jordan Bayles 2024-09-09 19:08:33 -07:00 committed by GitHub
commit dcd7aeac14
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 148 additions and 45 deletions

View File

@ -1,5 +1,5 @@
name: clang-format check name: clang-format check
on: [check_run, push] on: [check_run, pull_request, push]
jobs: jobs:
formatting-check: formatting-check:

18
.github/workflows/cmake.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: cmake
on: [check_run, push, pull_request]
jobs:
cmake-publish:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- name: checkout project
uses: actions/checkout@v4
- name: build project
uses: threeal/cmake-action@v2.0.0

View File

@ -1,9 +1,9 @@
name: meson build and test name: meson build and test
run-name: update pushed to ${{ github.ref }} run-name: update pushed to ${{ github.ref }}
on: [check_run, push] on: [check_run, push, pull_request]
jobs: jobs:
publish: meson-publish:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
@ -32,7 +32,7 @@ jobs:
ninja-version: 1.11.1.1 ninja-version: 1.11.1.1
action: test action: test
coverage: meson-coverage:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@ -54,16 +54,6 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# ---------------------------------------------------------------------------
# use ccache if found, has to be done before project()
# ---------------------------------------------------------------------------
find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin)
if(CCACHE_EXECUTABLE)
message(STATUS "use ccache")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE)
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE)
endif()
project(jsoncpp project(jsoncpp
# Note: version must be updated in three places when doing a release. This # Note: version must be updated in three places when doing a release. This
# annoying process ensures that amalgamate, CMake, and meson all report the # annoying process ensures that amalgamate, CMake, and meson all report the
@ -103,7 +93,9 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.")
endif() endif()
set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL") if(JSONCPP_USE_SECURE_MEMORY)
add_definitions("-DJSONCPP_USE_SECURE_MEMORY=1")
endif()
configure_file("${PROJECT_SOURCE_DIR}/version.in" configure_file("${PROJECT_SOURCE_DIR}/version.in"
"${PROJECT_BINARY_DIR}/version" "${PROJECT_BINARY_DIR}/version"

17
SECURITY.md Normal file
View File

@ -0,0 +1,17 @@
# Security Policy
If you have discovered a security vulnerability in this project, please report it
privately. **Do not disclose it as a public issue.** This gives us time to work with you
to fix the issue before public exposure, reducing the chance that the exploit will be
used before a patch is released.
Please submit the report by filling out
[this form](https://github.com/open-source-parsers/jsoncpp/security/advisories/new).
Please provide the following information in your report:
- A description of the vulnerability and its impact
- How to reproduce the issue
This project is maintained by volunteers on a reasonable-effort basis. As such,
we ask that you give us 90 days to work on a fix before public exposure.

View File

@ -63,7 +63,7 @@ def amalgamate_source(source_top_dir=None,
""" """
print("Amalgamating header...") print("Amalgamating header...")
header = AmalgamationFile(source_top_dir) header = AmalgamationFile(source_top_dir)
header.add_text("/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/).") header.add_text("/// Json-cpp amalgamated header (https://github.com/open-source-parsers/jsoncpp/).")
header.add_text('/// It is intended to be used with #include "%s"' % header_include_path) header.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
header.add_file("LICENSE", wrap_in_comment=True) header.add_file("LICENSE", wrap_in_comment=True)
header.add_text("#ifndef JSON_AMALGAMATED_H_INCLUDED") header.add_text("#ifndef JSON_AMALGAMATED_H_INCLUDED")
@ -90,7 +90,7 @@ def amalgamate_source(source_top_dir=None,
forward_header_include_path = base + "-forwards" + ext forward_header_include_path = base + "-forwards" + ext
print("Amalgamating forward header...") print("Amalgamating forward header...")
header = AmalgamationFile(source_top_dir) header = AmalgamationFile(source_top_dir)
header.add_text("/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).") header.add_text("/// Json-cpp amalgamated forward header (https://github.com/open-source-parsers/jsoncpp/).")
header.add_text('/// It is intended to be used with #include "%s"' % forward_header_include_path) header.add_text('/// It is intended to be used with #include "%s"' % forward_header_include_path)
header.add_text("/// This header provides forward declaration for all JsonCpp types.") header.add_text("/// This header provides forward declaration for all JsonCpp types.")
header.add_file("LICENSE", wrap_in_comment=True) header.add_file("LICENSE", wrap_in_comment=True)
@ -112,7 +112,7 @@ def amalgamate_source(source_top_dir=None,
print("Amalgamating source...") print("Amalgamating source...")
source = AmalgamationFile(source_top_dir) source = AmalgamationFile(source_top_dir)
source.add_text("/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).") source.add_text("/// Json-cpp amalgamated source (https://github.com/open-source-parsers/jsoncpp/).")
source.add_text('/// It is intended to be used with #include "%s"' % header_include_path) source.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
source.add_file("LICENSE", wrap_in_comment=True) source.add_file("LICENSE", wrap_in_comment=True)
source.add_text("") source.add_text("")

View File

@ -25,7 +25,7 @@ int main() {
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root, if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root,
&err)) { &err)) {
std::cout << "error" << std::endl; std::cout << "error: " << err << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }

View File

@ -244,6 +244,12 @@ private:
*/ */
class JSON_API CharReader { class JSON_API CharReader {
public: public:
struct JSON_API StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};
virtual ~CharReader() = default; virtual ~CharReader() = default;
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document. The document must be a UTF-8 encoded string containing the * document. The document must be a UTF-8 encoded string containing the
@ -262,7 +268,12 @@ public:
* error occurred. * error occurred.
*/ */
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) = 0; String* errs);
/** \brief Returns a vector of structured errors encountered while parsing.
* Each parse call resets the stored list of errors.
*/
std::vector<StructuredError> getStructuredErrors() const;
class JSON_API Factory { class JSON_API Factory {
public: public:
@ -272,6 +283,20 @@ public:
*/ */
virtual CharReader* newCharReader() const = 0; virtual CharReader* newCharReader() const = 0;
}; // Factory }; // Factory
protected:
class Impl {
public:
virtual ~Impl() = default;
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) = 0;
virtual std::vector<StructuredError> getStructuredErrors() const = 0;
};
explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}
private:
std::unique_ptr<Impl> _impl;
}; // CharReader }; // CharReader
/** \brief Build a CharReader implementation. /** \brief Build a CharReader implementation.

View File

@ -18,10 +18,9 @@
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
(JSONCPP_VERSION_PATCH << 8)) (JSONCPP_VERSION_PATCH << 8))
#ifdef JSONCPP_USING_SECURE_MEMORY #if !defined(JSONCPP_USE_SECURE_MEMORY)
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY 0 #define JSONCPP_USING_SECURE_MEMORY 0
#endif
// If non-zero, the library zeroes any memory that it has allocated before // If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory. // it frees its memory.

View File

@ -1,5 +1,5 @@
cmake_policy(PUSH) cmake_policy(PUSH)
cmake_policy(VERSION 3.0) cmake_policy(VERSION 3.0...3.26)
@PACKAGE_INIT@ @PACKAGE_INIT@

View File

@ -73,7 +73,7 @@ if meson.is_subproject() or not get_option('tests')
subdir_done() subdir_done()
endif endif
python = import('python').find_installation() python = find_program('python3')
jsoncpp_test = executable( jsoncpp_test = executable(
'jsoncpp_test', files([ 'jsoncpp_test', files([

View File

@ -144,7 +144,7 @@ if(BUILD_STATIC_LIBS)
# avoid name clashes on windows as the shared import lib is also named jsoncpp.lib # avoid name clashes on windows as the shared import lib is also named jsoncpp.lib
if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS)
if (MSVC) if (WIN32)
set(STATIC_SUFFIX "_static") set(STATIC_SUFFIX "_static")
else() else()
set(STATIC_SUFFIX "") set(STATIC_SUFFIX "")

View File

@ -878,17 +878,12 @@ class OurReader {
public: public:
using Char = char; using Char = char;
using Location = const Char*; using Location = const Char*;
struct StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};
explicit OurReader(OurFeatures const& features); explicit OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root, bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true); bool collectComments = true);
String getFormattedErrorMessages() const; String getFormattedErrorMessages() const;
std::vector<StructuredError> getStructuredErrors() const; std::vector<CharReader::StructuredError> getStructuredErrors() const;
private: private:
OurReader(OurReader const&); // no impl OurReader(OurReader const&); // no impl
@ -1836,10 +1831,11 @@ String OurReader::getFormattedErrorMessages() const {
return formattedMessage; return formattedMessage;
} }
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { std::vector<CharReader::StructuredError>
std::vector<OurReader::StructuredError> allErrors; OurReader::getStructuredErrors() const {
std::vector<CharReader::StructuredError> allErrors;
for (const auto& error : errors_) { for (const auto& error : errors_) {
OurReader::StructuredError structured; CharReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_; structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_; structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_; structured.message = error.message_;
@ -1849,20 +1845,36 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
} }
class OurCharReader : public CharReader { class OurCharReader : public CharReader {
bool const collectComments_;
OurReader reader_;
public: public:
OurCharReader(bool collectComments, OurFeatures const& features) OurCharReader(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {} : CharReader(
bool parse(char const* beginDoc, char const* endDoc, Value* root, std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
String* errs) override {
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); protected:
if (errs) { class OurImpl : public Impl {
*errs = reader_.getFormattedErrorMessages(); public:
OurImpl(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {}
bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) override {
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
if (errs) {
*errs = reader_.getFormattedErrorMessages();
}
return ok;
} }
return ok;
} std::vector<CharReader::StructuredError>
getStructuredErrors() const override {
return reader_.getStructuredErrors();
}
private:
bool const collectComments_;
OurReader reader_;
};
}; };
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
@ -1952,6 +1964,16 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
//! [CharReaderBuilderDefaults] //! [CharReaderBuilderDefaults]
} }
std::vector<CharReader::StructuredError>
CharReader::getStructuredErrors() const {
return _impl->getStructuredErrors();
}
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) {
return _impl->parse(beginDoc, endDoc, root, errs);
}
////////////////////////////////// //////////////////////////////////
// global functions // global functions

View File

@ -3917,6 +3917,36 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
example.size())); example.size()));
} }
struct ParseWithStructuredErrorsTest : JsonTest::TestCase {
void testErrors(
const std::string& doc, bool success,
const std::vector<Json::CharReader::StructuredError>& expectedErrors) {
Json::CharReaderBuilder b;
CharReaderPtr reader(b.newCharReader());
Json::Value root;
JSONTEST_ASSERT_EQUAL(
reader->parse(doc.data(), doc.data() + doc.length(), &root, nullptr),
success);
auto actualErrors = reader->getStructuredErrors();
JSONTEST_ASSERT_EQUAL(expectedErrors.size(), actualErrors.size());
for (std::size_t i = 0; i < actualErrors.size(); i++) {
const auto& a = actualErrors[i];
const auto& e = expectedErrors[i];
JSONTEST_ASSERT_EQUAL(a.offset_start, e.offset_start);
JSONTEST_ASSERT_EQUAL(a.offset_limit, e.offset_limit);
JSONTEST_ASSERT_STRING_EQUAL(a.message, e.message);
}
}
};
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, success) {
testErrors("{}", true, {});
}
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, singleError) {
testErrors("{ 1 : 2 }", false, {{2, 3, "Missing '}' or object member name"}});
}
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
JsonTest::Runner runner; JsonTest::Runner runner;