Skip to content

Compliance: Remove RapidJson dependency #131478

Open

Description

@GrabYourPitchforks

tl;dr: We need to remove our dependency on RapidJson in .NET 12. We should also strongly consider removing it from servicing branches after we stabilize its removal from .NET 12.


There's a coming compliance effort within MSFT to rid repos of out-of-date / unsupported dependencies. The first wave of this will almost certainly involve flagging usage of RapidJson, which is generally viewed as an abandoned project.

(Edit - we're already receiving alerts on this. What's being proposed is enforcement.)

To be clear: our own usage of RapidJson is secure, but the amount of paperwork and toil that's going to be required to keep this dependency around is almost certainly not going to be worth our time. Additionally, since RapidJson presumably shows up in our SBOMs, customers who run their own compliance scans (or who outsource such scans to third-party tooling) will start receiving similar alerts as the industry at large moves toward reducing stale dependencies. We've seen this before with complaints re: out-of-date versions of zlib; even though customers were never realistically exposed to any vulnerability, it simply caused too much pain for too many parties, and we changed our servicing policy to accommodate it.

Activity

  1. dotnet-policy-service commented on Jul 28, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @dotnet/area-meta
    See info in area-owners.md if you want to be subscribed.

  2. jkoritzinsky commented on Jul 28, 2026

    @jkoritzinsky
    Member

    @GrabYourPitchforks if I'm reading the SDL guidance correctly, the approved JSON serializer for C++ is https://github.com/nlohmann/json, correct?

  3. JakeYallop commented on Jul 29, 2026

    @JakeYallop
    Contributor

    I'm not suggesting I have a workaround here, but I've written a couple of apps where I've wanted fast start up.

    Will this change slow down app startup, and do we know by how much it might regress for typical (primarily R2R'd if you want fast startup) apps?

  4. elinor-fung commented on Jul 29, 2026

    @elinor-fung
    Member

    @am11 also had the suggestion of trying to switch the components that use it (hostfxr, hostpolicy`) to Native AOT, so we'd be using System.Text.Json for JSON parsing. Aside from just the risk of a large rewrite, startup perf would probably be the deciding factor for whether or not that is really an option (we know size would increase). That wouldn't be something I'd want to put into servicing branches though.

    Will this change slow down app startup

    We'll definitely want to measure any impact here.

  5. am11 commented on Jul 29, 2026

    @am11
    Member

    We can ask copilot to grab main...am11:runtime:feature/managed-corehost and apply over to main branch (incorporating recent refactoring). I think we will get the startup numbers out in few hours. The idea is; apphost, nethost and singlefilehost remain in C while the rest of muxer etc. where RapidJSON is used can be converted to NativeAOT.

  6. MichalPetryka commented on Jul 30, 2026

    @MichalPetryka
    Contributor

    switch the components that use it (hostfxr, hostpolicy`) to Native AOT, so we'd be using System.Text.Json for JSON parsing. Aside from just the risk of a large rewrite, startup perf would probably be the deciding factor for whether or not that is really an option (we know size would increase).

    I'd assume the permanent overhead from 2nd GC, threadpool and such would be the bigger problem with this.

  7. added this to the 12.0.0 milestone on Jul 30, 2026
  8. removed
    untriagedNew issue has not been triaged by the area owner
    on Jul 30, 2026
  9. am11 commented on Aug 2, 2026

    @am11
    Member

    Middle ground is to just offload JSON related interactions to an external lib. We can add something like src/native/managed/Microsoft.NET.HostActivationContext to produce libhostactivationcontext that fills out this contract:

    #ifndef HOST_ACTIVATION_H
    #define HOST_ACTIVATION_H
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #include <stddef.h>
    #include <stdbool.h>
    
    typedef struct host_activation_context {
        // --- Activation Targets & Global Settings ---
        const char* target_framework_moniker; // Points to string inside this block ("net8.0")
        const char* dev_runtime_config_path;  // Points to string inside this block if merged
        int         global_roll_forward;      // Corehost fallback roll-forward policy enum
        int         global_roll_forward_on_no_cand_fx; // Fallback policy on missing framework
    
        // --- Core Activation Flags ---
        bool   is_self_contained;             // Derived flag based on framework inclusions
        bool   cache_ready_to_run;            // Maps runtimeOptions.cacheReadyToRun
        bool   enable_exec_stack;             // Maps runtimeOptions.enableExecutionStack
    
        // --- Array 1: Configuration Properties / AppContext Switches ---
        size_t       prop_count;                    
        const char** prop_keys;               // Points to an array of string pointers inside this block
        const char** prop_vals;               // Points to an array of string pointers inside this block
    
        // --- Array 2: Assembly Probing Paths ---
        size_t       probe_paths_count;             
        const char** probe_paths;             // Points to an array of string pointers inside this block
    
        // --- Array 3: Primary Framework Dependencies ---
        size_t       fxr_count;                      
        const char** fxr_names;               // Points to framework name string array inside this block
        const char** fxr_versions;            // Points to framework version string array inside this block
        bool*        fxr_apply_patches;       // Points to array of apply_patches boolean state flags
        int*         fxr_roll_forwards;       // Points to array of roll_forward enum integers
        int*         fxr_rf_on_no_candidates; // Points to array of roll_forward_on_no_candidate_fx enums
        bool*        fxr_prefer_releases;     // Points to array of prefer_release evaluation flags
    
        // --- Array 4: Included / Application-Local Frameworks ---
        size_t       fxr_incl_count;                 
        const char** fxr_incl_names;          // Points to included framework name string array
        const char** fxr_incl_versions;       // Points to included framework version string array
        bool*        fxr_incl_apply_patches;  // Points to array of apply_patches flags 
        int*         fxr_incl_roll_forwards;  // Points to array of roll_forward enums 
        int*         fxr_incl_rf_on_no_cands; // Points to array of roll_forward_on_no_candidate_fx enums
        bool*        fxr_incl_prefer_releases;// Points to array of prefer_release flags 
    } host_activation_context_t;
    
    /**
     * Parses the specified target runtimeconfig.json file path and automatically
     * handles companion .dev.json lookups, setting overrides, and flattening.
     *
     * @param config_path         [in]  The platform-specific path to the json configuration file.
     * @param out_bytes_allocated [out] Receives the absolute total memory size of the single chunk.
     *                                  Can be passed to another process or used for diagnostics.
     * @return A single contiguous allocated block pointer, or NULL if parsing fails.
     */
    host_activation_context_t* host_activation_context_create(
        const char* config_path, 
        size_t* out_bytes_allocated
    );
    
    /**
     * Releases the continuous memory tracking block completely.
     * Because the allocation engine enforces zero-fragmentation, this can 
     * also be directly cleared using standard system free().
     *
     * @param context Handle to the active runtime configuration context.
     */
    void host_activation_context_free(host_activation_context_t* context);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif // HOST_ACTIVATION_H

    Today, all JSON related ops are handled before the runtime is initialized so we can concentrate them to a single call to a component "fill me this contract" then use that object for rest of the execution. To safely unload it after the call (and before initializing the runtime), here is a bit brittle (but working) solution: #64629 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions