Vector35 / Vector35/binaryninja-api

Performance Issue when a Python DataRenderer is registered

Open
#3,082 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Component: UI Effort: Medium Impact: Medium
Dominant language
C++
Stars
1.3k
Forks
298
Avg merge
5d 5h
Merged PRs (30d)
19

Description

Version and Platform (required):

  • Binary Ninja Version: 3.0.3357-dev
  • OS: macOS
  • OS Version: 12.3.1
  • CPU Architecture x64

Bug Description:
When a python DataRenderer is registered, scrolling through large arrays of structures becomes unusably slow.

Steps To Reproduce:

  1. Open a new binaryninja. It's fine if no python plugins are installed or it's started with -p.
  2. Create a file: truncate -s 65536 64kzeros.bin
  3. Open the file with binaryninja.
  4. Open Linear View.
  5. In the types editor, add a struct of size 0x100 named struct_1. Make sure it has multiple fields. More fields will increase the slowdown later on. The following structure is a good example:
    struct struct_1 {
      uint8_t field_0;
      uint8_t field_1;
      uint8_t field_2;
      uint8_t field_3;
      uint8_t field_4;
      uint8_t field_5;
      uint8_t field_6;
      uint8_t field_7;
      uint8_t field_8;
      uint8_t field_9;
      uint8_t field_a;
      uint8_t field_b;
      uint8_t field_c;
      uint8_t field_d;
      uint8_t field_e;
      uint8_t field_f;
      uint8_t field_10;
      uint8_t field_11;
      uint8_t field_12;
      uint8_t field_13;
      uint8_t field_14;
      uint8_t field_15;
      uint8_t field_16;
      uint8_t field_17;
      uint8_t field_18;
      uint8_t field_19;
      uint8_t field_1a;
      uint8_t field_1b;
      uint8_t field_1c;
      uint8_t field_1d;
      uint8_t field_1e;
      uint8_t field_1f;
      uint8_t field_20;
      uint8_t field_21;
      uint8_t field_22;
      uint8_t field_23;
      uint8_t field_24;
      uint8_t field_25;
      uint8_t field_26;
      uint8_t field_27;
      uint8_t field_28;
      uint8_t field_29;
      uint8_t field_2a;
      uint8_t field_2b;
      uint8_t field_2c;
      uint8_t field_2d;
      uint8_t field_2e;
      uint8_t field_2f;
      uint8_t field_30;
      uint8_t field_31;
      uint8_t field_32;
      uint8_t field_33;
      uint8_t field_34;
      uint8_t field_35;
      uint8_t field_36;
      uint8_t field_37;
      uint8_t field_38;
      uint8_t field_39;
      uint8_t field_3a;
      uint8_t field_3b;
      uint8_t field_3c;
      uint8_t field_3d;
      uint8_t field_3e;
      uint8_t field_3f;
      uint8_t field_40;
      uint8_t field_41;
      uint8_t field_42;
      uint8_t field_43;
      uint8_t field_44;
      uint8_t field_45;
      uint8_t field_46;
      uint8_t field_47;
      uint8_t field_48;
      uint8_t field_49;
      uint8_t field_4a;
      uint8_t field_4b;
      uint8_t field_4c;
      uint8_t field_4d;
      uint8_t field_4e;
      uint8_t field_4f;
      uint8_t field_50;
      uint8_t field_51;
      uint8_t field_52;
      uint8_t field_53;
      uint8_t field_54;
      uint8_t field_55;
      uint8_t field_56;
      uint8_t field_57;
      uint8_t field_58;
      uint8_t field_59;
      uint8_t field_5a;
      uint8_t field_5b;
      uint8_t field_5c;
      uint8_t field_5d;
      uint8_t field_5e;
      uint8_t field_5f;
      uint8_t field_60;
      uint8_t field_61;
      uint8_t field_62;
      uint8_t field_63;
      uint8_t field_64;
      uint8_t field_65;
      uint8_t field_66;
      uint8_t field_67;
      uint8_t field_68;
      uint8_t field_69;
      uint8_t field_6a;
      uint8_t field_6b;
      uint8_t field_6c;
      uint8_t field_6d;
      uint8_t field_6e;
      uint8_t field_6f;
      uint8_t field_70;
      uint8_t field_71;
      uint8_t field_72;
      uint8_t field_73;
      uint8_t field_74;
      uint8_t field_75;
      uint8_t field_76;
      uint8_t field_77;
      uint8_t field_78;
      uint8_t field_79;
      uint8_t field_7a;
      uint8_t field_7b;
      uint8_t field_7c;
      uint8_t field_7d;
      uint8_t field_7e;
      uint8_t field_7f;
      uint8_t field_80;
      uint8_t field_81;
      uint8_t field_82;
      uint8_t field_83;
      uint8_t field_84;
      uint8_t field_85;
      uint8_t field_86;
      uint8_t field_87;
      uint8_t field_88;
      uint8_t field_89;
      uint8_t field_8a;
      uint8_t field_8b;
      uint8_t field_8c;
      uint8_t field_8d;
      uint8_t field_8e;
      uint8_t field_8f;
      uint8_t field_90;
      uint8_t field_91;
      uint8_t field_92;
      uint8_t field_93;
      uint8_t field_94;
      uint8_t field_95;
      uint8_t field_96;
      uint8_t field_97;
      uint8_t field_98;
      uint8_t field_99;
      uint8_t field_9a;
      uint8_t field_9b;
      uint8_t field_9c;
      uint8_t field_9d;
      uint8_t field_9e;
      uint8_t field_9f;
      uint8_t field_a0;
      uint8_t field_a1;
      uint8_t field_a2;
      uint8_t field_a3;
      uint8_t field_a4;
      uint8_t field_a5;
      uint8_t field_a6;
      uint8_t field_a7;
      uint8_t field_a8;
      uint8_t field_a9;
      uint8_t field_aa;
      uint8_t field_ab;
      uint8_t field_ac;
      uint8_t field_ad;
      uint8_t field_ae;
      uint8_t field_af;
      uint8_t field_b0;
      uint8_t field_b1;
      uint8_t field_b2;
      uint8_t field_b3;
      uint8_t field_b4;
      uint8_t field_b5;
      uint8_t field_b6;
      uint8_t field_b7;
      uint8_t field_b8;
      uint8_t field_b9;
      uint8_t field_ba;
      uint8_t field_bb;
      uint8_t field_bc;
      uint8_t field_bd;
      uint8_t field_be;
      uint8_t field_bf;
      uint8_t field_c0;
      uint8_t field_c1;
      uint8_t field_c2;
      uint8_t field_c3;
      uint8_t field_c4;
      uint8_t field_c5;
      uint8_t field_c6;
      uint8_t field_c7;
      uint8_t field_c8;
      uint8_t field_c9;
      uint8_t field_ca;
      uint8_t field_cb;
      uint8_t field_cc;
      uint8_t field_cd;
      uint8_t field_ce;
      uint8_t field_cf;
      uint8_t field_d0;
      uint8_t field_d1;
      uint8_t field_d2;
      uint8_t field_d3;
      uint8_t field_d4;
      uint8_t field_d5;
      uint8_t field_d6;
      uint8_t field_d7;
      uint8_t field_d8;
      uint8_t field_d9;
      uint8_t field_da;
      uint8_t field_db;
      uint8_t field_dc;
      uint8_t field_dd;
      uint8_t field_de;
      uint8_t field_df;
      uint8_t field_e0;
      uint8_t field_e1;
      uint8_t field_e2;
      uint8_t field_e3;
      uint8_t field_e4;
      uint8_t field_e5;
      uint8_t field_e6;
      uint8_t field_e7;
      uint8_t field_e8;
      uint8_t field_e9;
      uint8_t field_ea;
      uint8_t field_eb;
      uint8_t field_ec;
      uint8_t field_ed;
      uint8_t field_ee;
      uint8_t field_ef;
      uint8_t field_f0;
      uint8_t field_f1;
      uint8_t field_f2;
      uint8_t field_f3;
      uint8_t field_f4;
      uint8_t field_f5;
      uint8_t field_f6;
      uint8_t field_f7;
      uint8_t field_f8;
      uint8_t field_f9;
      uint8_t field_fa;
      uint8_t field_fb;
      uint8_t field_fc;
      uint8_t field_fd;
      uint8_t field_fe;
      uint8_t field_ff;
    }
    
  6. At address 0, define an array of struct struct_1: struct struct_1[0x100].
  7. Scroll around a bit using scroll wheel, the scroll bar, or navigate to addresses using g.
  8. Define a DataRenderer, by pasting the following into the Python console.
    class MakeEverythingSlow(DataRenderer):
        def __init__(self):
            DataRenderer.__init__(self)
        def perform_is_valid_for_data(self, ctxt, view, addr, typ, context):
            return False
        def perform_get_lines_for_data(self, ctxt, view, addr, typ, prefix, width, context):
            return []
        def __del__(self):
            pass
    
    MakeEverythingSlow().register_type_specific()
    
  9. Scroll around a bit using scroll wheel, scroll bar, or navigate to addresses using g. Observe everything is now significantly slower.

Expected Behavior:
Scrolling around and navigating the binary is possible and binaryninja stays responsive.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the slowdown with the Python console DataRenderer example, the large struct array, and the listed scrolling paths. Start by tracing the DataRenderer registration and its perform_is_valid_for_data and perform_get_lines_for_data callbacks. Done means scrolling and address navigation remain responsive after registering the renderer.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
performance, reverse-engineering
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.