glaze icon indicating copy to clipboard operation
glaze copied to clipboard

json pointer more than one level issue with -fsanitize=null check

Open p-selini opened this issue 10 months ago • 1 comments

I have a code like this: auto z = glz::get_as_json<uint64_t, "/conn_idx/f">(buffer); which gives out this error:

error: '(((const __gnu_cxx::char_traits<char>::char_type*)(&*(const char (*)[12])((char*)&_ZTAXtlN3glz14string_literalILm12EEEtlA12_cLc47ELc99ELc111ELc110ELc110ELc95ELc105ELc100ELc120ELc47ELc102EEEE + offsetof(const glz::string_literal<12>,glz::string_literal<12>::value[9])))) != 0)' is not a constant expression
   88 |           if (__p)

My glaze is 5.0 and I use latest gcc and c++23 from godbolt here: Sample

From what I see, if I only have /conn_idx without the second path I am fine. If I take out the -fsanitize=null flag I am also fine.

The comment out code: //auto z = glz::get<int>(buffer,"/conn_idx/f"); If I uncomment it and comment out the get_as_json it will compile but has segmentation fault.

I think sanitize build has issue. but the get<int> segfault could also be another issue. Do you agree?

p-selini avatar Apr 21 '25 22:04 p-selini

Thanks for reporting this! Will try to look into it soon.

stephenberry avatar Apr 21 '25 22:04 stephenberry

Bumping this. Can you check if get<...> issue can be fixed? It happens even without sanitize build so it is more serious. Here is the problem using godbolt : get pointer crash

p-selini avatar Apr 24 '25 17:04 p-selini

@p-selini, your example is using glz::get incorrectly, and the function is returning an expected with an error code. Your segfault is caused because you aren't checking if the result has an error.

If you run this code:

std::string buffer = R"({"conn_idx":{"f":10}})";
auto z = glz::get<int>(buffer,"/conn_idx/f");
std::cout << glz::format_error(z) <<"\n";

You'll get the output: get_nonexistent_json_ptr

The problem is that the first parameter you pass to glz::get should be your equivalent JSON C++ type. The JSON pointer you pass in is referring to an object, so the C++ structure you pass in must be a map or struct.

This code works:

struct conn_idx_t
{
    int f = 10;
};

struct connection_t
{
    conn_idx_t conn_idx{};
};

int main() {
    connection_t conn{};
    auto z = glz::get<int>(conn,"/conn_idx/f");
    std::cout << *z <<"\n";
    return 0;
}

stephenberry avatar Apr 24 '25 18:04 stephenberry

ok, this makes sense. but I don't have an object(connection_t) in this case, I only want to get a vanilla int through the path /conn_idx/f

p-selini avatar Apr 24 '25 18:04 p-selini

@p-selini, What you want is glz::get_as_json. This code works on compiler explorer:

#include <iostream>
#include <string>
#include <glaze/glaze.hpp>

int main() {
    std::string buffer = R"({"conn_idx":{"f":10}})";
    auto z = glz::get_as_json<uint64_t, "/conn_idx/f">(buffer);
    if (z) {
        std::cout << *z <<"\n";
    }
    else {
        std::cout << glz::format_error(z) <<"\n";
    }
    return 0;
}

stephenberry avatar Apr 24 '25 19:04 stephenberry

I see your issue is with -fsanitize=null. The output: is not a constant expression leads me to think that this is a compiler bug with that flag on. Because it is just not liking the compile time string logic, which works if the flag isn't included.

stephenberry avatar Apr 24 '25 19:04 stephenberry

I agree it is GCC compiler issue under sanitizer mode, clang seems to be fine. But what's the alternative under gcc sanitizer mode? The get as you said did not work in this scenario either.

p-selini avatar Apr 24 '25 21:04 p-selini

Can you use JMESPath? Or, do you need JSON Pointer syntax?

JMESPath documentation is here: https://github.com/stephenberry/glaze/blob/main/docs/JMESPath.md

stephenberry avatar Apr 25 '25 13:04 stephenberry

I sure can, I didn't try this since it says partial supported. I imagine the latency is on par with get_as_json ? Here is the demo that it works even under the sanitizer, wondering what's the difference between this and get_as_json since syntax looks pretty similar from user's perspective?

p-selini avatar Apr 25 '25 17:04 p-selini

JMESPath is a much bigger spec than JSON Pointer syntax, so its partial support is still decent. Under the hood the implementations are quite different, JMESPath allows more efficient implementations because there is less ambiguity.

stephenberry avatar Apr 25 '25 21:04 stephenberry