Skip to content

Commit

Permalink
Merge branch 'master' into write-string
Browse files Browse the repository at this point in the history
  • Loading branch information
baylesj authored Sep 10, 2024
2 parents 8532e06 + 2072e2b commit b377070
Show file tree
Hide file tree
Showing 16 changed files with 151 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/clang-format.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: clang-format check
on: [check_run, push]
on: [check_run, pull_request, push]

jobs:
formatting-check:
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
@@ -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/[email protected]

6 changes: 3 additions & 3 deletions .github/workflows/meson.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: meson build and test
run-name: update pushed to ${{ github.ref }}
on: [check_run, push]
on: [check_run, push, pull_request]

jobs:
publish:
meson-publish:
runs-on: ${{ matrix.os }}

strategy:
Expand Down Expand Up @@ -32,7 +32,7 @@ jobs:
ninja-version: 1.11.1.1
action: test

coverage:
meson-coverage:
runs-on: ubuntu-latest

steps:
Expand Down
14 changes: 3 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,6 @@ endif()

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
# Note: version must be updated in three places when doing a release. This
# annoying process ensures that amalgamate, CMake, and meson all report the
Expand Down Expand Up @@ -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.")
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"
"${PROJECT_BINARY_DIR}/version"
Expand Down
17 changes: 17 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 3 additions & 3 deletions amalgamate.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def amalgamate_source(source_top_dir=None,
"""
print("Amalgamating header...")
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_file("LICENSE", wrap_in_comment=True)
header.add_text("#ifndef JSON_AMALGAMATED_H_INCLUDED")
Expand All @@ -90,7 +90,7 @@ def amalgamate_source(source_top_dir=None,
forward_header_include_path = base + "-forwards" + ext
print("Amalgamating forward header...")
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("/// This header provides forward declaration for all JsonCpp types.")
header.add_file("LICENSE", wrap_in_comment=True)
Expand All @@ -112,7 +112,7 @@ def amalgamate_source(source_top_dir=None,

print("Amalgamating source...")
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_file("LICENSE", wrap_in_comment=True)
source.add_text("")
Expand Down
2 changes: 1 addition & 1 deletion example/readFromString/readFromString.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int main() {
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root,
&err)) {
std::cout << "error" << std::endl;
std::cout << "error: " << err << std::endl;
return EXIT_FAILURE;
}
}
Expand Down
4 changes: 2 additions & 2 deletions include/PreventInSourceBuilds.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# This function will prevent in-source builds
function(AssureOutOfSourceBuilds)
# make sure the user doesn't play dirty with symlinks
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
get_filename_component(srcdir "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_CURRENT_BINARY_DIR}" REALPATH)

# disallow in-source builds
if("${srcdir}" STREQUAL "${bindir}")
Expand Down
27 changes: 26 additions & 1 deletion include/json/reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ class JSON_API Reader {
*/
class JSON_API CharReader {
public:
struct JSON_API StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};

virtual ~CharReader() = default;
/** \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
Expand All @@ -262,7 +268,12 @@ class JSON_API CharReader {
* error occurred.
*/
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 {
public:
Expand All @@ -272,6 +283,20 @@ class JSON_API CharReader {
*/
virtual CharReader* newCharReader() const = 0;
}; // 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

/** \brief Build a CharReader implementation.
Expand Down
5 changes: 2 additions & 3 deletions include/json/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
(JSONCPP_VERSION_PATCH << 8))

#ifdef JSONCPP_USING_SECURE_MEMORY
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#if !defined(JSONCPP_USE_SECURE_MEMORY)
#define JSONCPP_USING_SECURE_MEMORY 0
#endif
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.

Expand Down
2 changes: 1 addition & 1 deletion jsoncppConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_policy(PUSH)
cmake_policy(VERSION 3.0)
cmake_policy(VERSION 3.0...3.26)

@PACKAGE_INIT@

Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ if meson.is_subproject() or not get_option('tests')
subdir_done()
endif

python = import('python').find_installation()
python = find_program('python3')

jsoncpp_test = executable(
'jsoncpp_test', files([
Expand Down
2 changes: 1 addition & 1 deletion src/lib_json/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ if(BUILD_STATIC_LIBS)

# 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 (MSVC)
if (WIN32)
set(STATIC_SUFFIX "_static")
else()
set(STATIC_SUFFIX "")
Expand Down
60 changes: 41 additions & 19 deletions src/lib_json/json_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -877,17 +877,12 @@ class OurReader {
public:
using Char = char;
using Location = const Char*;
struct StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};

explicit OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true);
String getFormattedErrorMessages() const;
std::vector<StructuredError> getStructuredErrors() const;
std::vector<CharReader::StructuredError> getStructuredErrors() const;

private:
OurReader(OurReader const&); // no impl
Expand Down Expand Up @@ -1834,10 +1829,11 @@ String OurReader::getFormattedErrorMessages() const {
return formattedMessage;
}

std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
std::vector<OurReader::StructuredError> allErrors;
std::vector<CharReader::StructuredError>
OurReader::getStructuredErrors() const {
std::vector<CharReader::StructuredError> allErrors;
for (const auto& error : errors_) {
OurReader::StructuredError structured;
CharReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_;
Expand All @@ -1847,20 +1843,36 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
}

class OurCharReader : public CharReader {
bool const collectComments_;
OurReader reader_;

public:
OurCharReader(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();
: CharReader(
std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}

protected:
class OurImpl : public Impl {
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_); }
Expand Down Expand Up @@ -1950,6 +1962,16 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
//! [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

Expand Down
2 changes: 1 addition & 1 deletion src/lib_json/json_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
return false;
}
if (removed)
*removed = it->second;
*removed = std::move(it->second);
ArrayIndex oldSize = size();
// shift left all items left, into the place of the "removed"
for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
Expand Down
30 changes: 30 additions & 0 deletions src/test_lib_json/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3917,6 +3917,36 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
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[]) {
JsonTest::Runner runner;

Expand Down

0 comments on commit b377070

Please sign in to comment.