aardappel / lobster

The Lobster Programming Language

Home Page:http://strlen.com/lobster

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Crash when maybe breaking flexbuffers_value_to_binary's rules.

MortimerSnerd opened this issue · comments

I'd been using flexbuffers_value_to_binary to write out a class as a quick serialization method. Works. I added a member to that class that's a user defined struct, and it started crashing. I didn't immediately catch on the added field was the issue, as it was with a batch of other edits.

Example:

import vec

struct rect:
   tl: xy_f
   br: xy_f

class Wrapper:
   r = rect{xy_0, xy_x}

let jimmy = Wrapper{}
let bv = flexbuffers_value_to_binary(jimmy)

print("huh {bv}")

Since the docs specifically say flexbuffers_value_to_binary should be called with a reference type, I suspect I'm just doing something that's unsupported by including a user defined struct as one of the fields. That's fine, but it's not so obvious from the assertion:

Assertion failed: i < size(), file C:\src\lobster\dev\include\flatbuffers\vector.h, line 169

Flatbuffers doesn't really have the information to give a better message at that point. I was going to try and add a check, but stepping through it in the debugger convinced me that I don't know enough about what's going on there to do it. When it went to write out the "r" field in Wrapper, it was like my user defined rect type wasn't even there, and it just wrote out the xy_f of the first field of the rect.

Here's the stack I just copied out of Visual Studio:

 	lobster.exe!_wassert(const wchar_t * expression, const wchar_t * file_name, unsigned int line_number) Line 444	C++
 	lobster.exe!flatbuffers::Vector<flatbuffers::Offset<bytecode::Field>>::Get(unsigned int i) Line 169	C++
 	lobster.exe!lobster::VM::LookupField(int stidx, __int64 fieldn) Line 458	C++
 	lobster.exe!lobster::LObject::ToFlexBuffer(lobster::VM & vm, flexbuffers::Builder & builder) Line 465	C++
 	lobster.exe!lobster::Value::ToFlexBuffer(lobster::VM & vm, flexbuffers::Builder & builder, lobster::ValueType t) Line 263	C++
 	lobster.exe!lobster::ElemToFlexBuffer(lobster::VM & vm, flexbuffers::Builder & builder, const lobster::TypeInfo & ti, __int64 & i, __int64 width, const lobster::Value * elems, bool is_vector) Line 450	C++
 	lobster.exe!lobster::LObject::ToFlexBuffer(lobster::VM & vm, flexbuffers::Builder & builder) Line 467	C++
 	lobster.exe!lobster::Value::ToFlexBuffer(lobster::VM & vm, flexbuffers::Builder & builder, lobster::ValueType t) Line 263	C++
 	lobster.exe!`lobster::AddReader'::`2'::<lambda_2>::operator()(lobster::Value * & __formal, lobster::VM & vm, lobster::Value & val) Line 376	C++
 	lobster.exe!_Closure_wrapper_09b7fc5e_2::<lambda_invoker_cdecl>(lobster::Value * & __p1, lobster::VM & __p2, lobster::Value & __p3) Line 380	C++
 	lobster.exe!lobster::U_BCALLRET1(lobster::VM & vm, lobster::Value * sp, int nfi, int has_ret) Line 252	C++
 	lobster.exe!CVM_BCALLRET1(lobster::VM * vm, lobster::Value * sp, int _a, int _b) Line 667	C++
 	[External Code]	
 	lobster.exe!lobster::VM::EvalProgram() Line 390	C++
 	lobster.exe!`lobster::RunTCC'::`2'::<lambda_1>::operator()(void * * exports) Line 355	C++
 	[External Code]	
 	lobster.exe!lobster::RunC(const char * source, const char * object_name, std::string & error, const void * * imports, const char * * export_names, std::function<bool __cdecl(void * *)> runf) Line 70	C++
 	lobster.exe!lobster::RunTCC(lobster::NativeRegistry & nfr, std::basic_string_view<char,std::char_traits<char>> bytecode_buffer, std::basic_string_view<char,std::char_traits<char>> fn, const char * object_name, std::vector<std::string,std::allocator<std::string>> && program_args, lobster::TraceMode trace, bool compile_only, std::string & error) Line 344	C++
 	lobster.exe!SDL_main(int argc, char * * argv) Line 210	C++
 	lobster.exe!main_getcmdline(...) Line 175	C
 	lobster.exe!main(int argc, char * * argv) Line 188	C

This should be supported.. this looks like a bug caused by the fact that we have nested structs here.

Unsure if it's helpful, but I noticed last night a similar crash with pass a class that had the same nested struct to im_edit_anything(). I assumed it was just the same problem that's at a higher level, if not I can open a real defect later.

Yes, the same bug is actually also when you do print jimmy.. it omits the rect, I will look at it right now.

Ok, small but significant fix: eefdbdc

It was basically thinking the xy_f structs were directly inside Wrapper, and this affected dynamic type inspection.

print jimmy now says Wrapper{rect{xy_f{0, 0}, xy_f{1.0, 0}}}, before it was Wrapper{xy_f{0, 0}, xy_f{1.0, 0}}

flexbuffers_value_to_binary doesn't crash anymore.

Tip: use set_print_quoted(true) when printing binary buffers like bv, you get the more readable "huh _type\x00\x07Wrapper\x00r\x00tl\x00x\x00y\x00\x02\x05\x04\x00\x03\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0E\x0Ebr\x00\x02\"!\x02\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x0E\x0E\x02\x1D?\x02\x01\x02\x10-&&\x02YK\x02\x01\x02W\x0B\x14$\x04$\x01" rather than just _type because it doesn't stop at the first 0.

Haven't tested im_edit_anything but I'm pretty sure that was the exact same problem.

Thanks for reporting!

I verified that this works. It does also fix the im_edit_everything. Thanks for the fixes.