Repository navigation
Conversation
From<&TVariant> only handled Int32 and Double, silently turning VTYPE_I2, VTYPE_UI1, VTYPE_UI2, VTYPE_ERROR and VTYPE_R4 into ParamValue::Empty. Per the Native API docs the platform stores integers in lVal and fractions in dblVal regardless of the tag, so those are read now. Adds unit tests covering every tag.
Taken from upstream feat/support-for-any-func-args-and-return, where they accompany the Any feature but are independent of it: elide the lifetime on This::get_component, make ParamValues::iter lifetime explicit, and allow the unused name_override field. Clears three of the four pre-existing clippy warnings. Also corrects the os_string_nil doc comment on unix, which still claimed there is no terminator after the previous commit added one.
ComponentWrapper assumes destroy sits right after the four interface pointers, but in Component five fields were declared in between, so destroy landed at offset 96 on x86_64 and 48 on x86 while the wrapper read offset 32 and 16. That slot holds memory_manager_ptr, which set_mem_manager fills with a live pointer to the platform allocator, so DestroyObject called it as a function. 1C died with c0000005 and DEP flag 8 at an address belonging to no loaded module. Move destroy up to the offset the wrapper expects and pin the layout with offset_of! assertions plus a create/destroy roundtrip test that runs on both x86_64 and i686.
A panic in add-in code used to unwind through the C++ frames of the platform, which aborts the process. Every callback in init_done, lang_extender, locale_base and user_lang_base now runs through a guard that catches it, reports it with AddError and returns the failure value the platform expects. set_mem_manager is left alone: it only copies a pointer. The add-in state is unknown after unwinding, so the component is poisoned on the first panic and every later call returns the fallback without touching it. init now stores connection_ptr before running add-in code. The field existed but was never populated, so the FFI layer had no way to reach AddError - which is also what makes a panic inside init itself reportable. Adds AppCapabilities for the SetPlatformCapabilities negotiation and tests for the guard, the poisoning and the negotiation.
The platform withholds message output and platform info from components that do not negotiate capabilities, so Connection::add_error was a silent no-op. extern_functions! already generated a PLATFORM_CAPABILITIES static for this but never emitted the function that fills it. The static loses its mut: AtomicI32 needs no unsafe access, and references to static mut become errors in edition 2024. Like the other four exports it uses extern C, which the x86 build confirms is the right convention for the DLL exports, while the vtable methods stay extern system.
ReportMessage pushes a line into the 1C message window through add_error, which only reaches the user now that capabilities are negotiated. Panic raises deliberately so the guard can be checked end to end; it poisons the component, so it has to be called last. README documents the guard, the poisoning and the panic = abort caveat.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The crash
The component brings 1C down when the platform unloads it. Reproduced on 1C 8.5.4.1306, both
x86 and x86_64.
destroy_componentreads the destructor pointer through a localComponentWrapperwhich assumesdestroysits right after the four interface pointers. InComponentfive fields are declared inbetween, so the real offset was 96 on x86_64 and 48 on x86, while the wrapper read 32 and 16. That
slot holds
memory_manager_ptr, whichset_mem_managerfills with a live pointer to the platformallocator — so
DestroyObjectcalled it as a function.Windows Error Reporting matches this exactly:
1CV8C.exe, event typeBEX,c0000005, DEP flag8,and
StackHashin P4, meaning the faulting address belongs to no loaded module.Pinned by a test rather than by inspection — this assertion fails on
main:The fix moves
destroyto the offset the wrapper expects and addsoffset_of!assertions plus acreate → destroy roundtrip test, both running on x86_64 and i686.
Panics
Every platform callback except
set_mem_managernow runs behind a guard. A panic in add-in code usedto unwind through the C++ frames of 1C and abort the process; now it is caught, reported through
AddError, and turned into the failure value the platform expects. The component is poisoned afterthe first panic, since its state is unknown once the stack has unwound.
initalso storesconnection_ptrbefore running add-in code. The field existed but was neverpopulated anywhere, so the FFI layer had no way to reach
AddError. This is what makes a panic insideinititself reportable.SetPlatformCapabilities
Now exported by
extern_functions!. Per the Native API documentation, without this export the platformwithholds message output — so
Connection::add_errorand the wholeMessageCodeenum were dead code.The pre-existing
PLATFORM_CAPABILITIESstatic loses itsmut, since references tostatic mutbecome errors in edition 2024.
tVariant conversion
From<&TVariant> for ParamValuehandled onlyInt32andDouble, silently turningVTYPE_I2,VTYPE_UI1,VTYPE_UI2,VTYPE_ERRORandVTYPE_R4intoParamValue::Empty. The docs note thatvalues arriving from the web client may come with any numeric type.
Taken from your
feat/support-for-any-func-args-and-return96954c4cherry-picked as is, with your authorship:os_string_nildid not append the terminator onunix while
get_strreads names including it, sofind_propandfind_methodcould never match onLinux. These fixes are independent of the
Anyfeature, so they are split out here.This::get_component, the explicit lifetime onParamValues::iter, and#[allow(dead_code)]onname_override. They clear three of the four pre-existing clippy warnings.Verification
cargo test --workspace— 84 passed, 0 failedcargo test -p native_api_1c_core --target i686-pc-windows-msvc— 15 passed, so the layoutassertions run on 32-bit too
cargo clippy --workspace --all-targets— one pre-existing warning left (string_utils.rs:42)cargo fmt --all -- --check— clean. Note thatfind_method.rsandfind_prop.rsstill make rustfmtabort with an internal
left behind trailing whitespaceerror, which predates this branchmethods work, and a deliberate panic is reported into the message window instead of killing 1C
Left alone
dtoris0in all four vtables. If the platform ever calls the virtual destructor instead ofDestroyObject, that is a jump to null with the same signature as the bug fixed here.panic = "abort"disables the guard entirely — noted in the README.VCRUNTIME140.dll), while the 1C docs askfor non-system runtimes to be linked statically and for a manifest in Windows components.