hgarrereyn / GraphFuzz

GraphFuzz is an experimental framework for building structure-aware, library API fuzzers.
https://hgarrereyn.github.io/GraphFuzz
MIT License
254 stars 25 forks source link

Schema for Super Class (w/ protected constructor)... #21

Closed yheechan closed 1 year ago

yheechan commented 1 year ago

I came across a problem while writing schema where...

  1. a super class has its constructor protected
  2. a class inherits a super class
  3. another class that inherits super class needs super class as its parameter in its constructor.

here is the example with three class.

class SUPERCLASS {
public:
    virtual ~SUPERCLASS();
    virtual void extra_function();
protected:
    // Constructor for sub-classes
    SUPERCLASS(int x, int y)
        : extra_field(x) { }
private:
    const int extra_field;
};

class SUBCLASS_A : public SUPERCLASS{
public:
    SUBCLASS_A(int x);
    ~SUBCLASS_A();
private:
    const int rand;
};

class SUBCLASS_B : public SUPERCLASS{
public:
    SUBCLASS_B(int x, SUPERCLASS sp);
    ~SUBCLASS_B();
private:
    const int rand;
};

It seems when trying to write a schema for the following,

  1. SUPERCLASS is not recognized to contain a initializer
  2. SUPERCLASS_B also not recognized to contain initializer due to needing SUPERCLASS in it parameter.

Is there are turn around to this circumstance? SUPERCLASS with protected constructor, complicates things in schema...

I am wanting SUPERCLASS in schema to eventually output classes that inherit it...

please request for schema attempt if wanted... eventually since SUBCLASS_B depends on a class that inherits SUPERCLASS, SUPERCLASS should be written in schema...

hgarrereyn commented 1 year ago

Hi @yheechan, there is not currently automatic support for handling subclasses like this. However as a workaround you can define a "downcast" method that tells GraphFuzz it is ok to convert a SUBCLASS_A into a SUPERCLASS. For example:

struct_SUPERCLASS:
  type: struct
  name: SUPERCLASS
  headers: ['lib.h']
  methods:
  - ~SUPERCLASS()
  - void extra_function()

struct_SUBCLASS_A:
  type: struct
  name: SUBCLASS_A
  headers: ['lib.h']
  methods:
  - SUBCLASS_A(int)
  - ~SUBCLASS_A()
  - downcast:
      inputs: ['SUBCLASS_A']
      outputs: ['SUPERCLASS']
      exec: |
        $o0 = $i0;

struct_SUBCLASS_B:
  type: struct
  name: SUBCLASS_B
  headers: ['lib.h']
  methods:
  - SUBCLASS_B(int, SUPERCLASS)
  - ~SUBCLASS_B()

It's not ideal because the result is that once you downcast a SUBCLASS_A, you cannot later upcast it (the information is lost).

Another option could be to define a duplicate constructor for SUBCLASS_B that explicitly mentions the subclasses, e.g.:

struct_SUBCLASS_B:
  type: struct
  name: SUBCLASS_B
  headers: ['lib.h']
  methods:
  - SUBCLASS_B(int, SUPERCLASS)
  - SUBCLASS_B(int, SUBCLASS_A)
  - ~SUBCLASS_B()

The benefit here is that you can use a SUBCLASS_A in the constructor and then continue to call SUBCLASS_A-specific methods on the object afterwards. But you may end up with many duplicated methods.

yheechan commented 1 year ago

Thank you for the straight forward explanation! I have understood both approach, with their give&takes. Will do this to try run some tests! šŸ˜„šŸ‘