json pointer more than one level issue with -fsanitize=null check
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?
Thanks for reporting this! Will try to look into it soon.
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, 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;
}
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, 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;
}
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.
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.
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
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?
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.