https://bugs.kde.org/show_bug.cgi?id=448087

            Bug ID: 448087
           Summary: rust-qt-binding-generator: Undefined Behaviour: One
                    can obtain a mutable reference to a Rust struct from
                    an immutable reference.
           Product: rust-qt-binding-generator
           Version: unspecified
          Platform: Other
                OS: All
            Status: REPORTED
          Severity: normal
          Priority: NOR
         Component: general
          Assignee: j...@vandenoever.info
          Reporter: a...@grois.info
  Target Milestone: ---

Created attachment 145205
  --> https://bugs.kde.org/attachment.cgi?id=145205&action=edit
example code ready to run cargo build

SUMMARY
By storing the Emitter in a RefCell one can create a mutable reference to the
struct the Emitter is associated with while an arbitrary number of immutable
references to the same struct may exist. If I understand the Rustonomicon
correctly, such a transmutation from & to &mut violates Rust's aliasing rules
and is undefined behaviour.

Let's assume a minimal example (also attached in a build-ready form):
-------------------
bindings.json
  {
      "cppFile": "src/Bindings.cpp",
      "rust": {
          "dir": "rust",
          "interfaceModule": "interface",
          "implementationModule": "implementation"
      },
      "objects": {
          "SomeQtObject" : {
              "type" : "Object",
              "properties" : {
                  "some_property" : {
                      "type" : "bool",
                      "write": true
                  }
              }
          }
      }
  }
-------------------
implementation.rs:
  use interface::*;

  pub struct SomeQtObject {
      emit : SomeQtObjectEmitter,
      emit2: std::cell::RefCell<SomeQtObjectEmitter>,
      some_property: bool,
  }
  impl SomeQtObjectTrait for SomeQtObject {
      fn new(mut emit: SomeQtObjectEmitter) -> SomeQtObject {
          let emit2 = emit.clone();
          SomeQtObject {
              emit,
              emit2 : std::cell::RefCell::new(emit2),
              some_property: false,
          }
      }
      fn emit(&mut self) -> &mut SomeQtObjectEmitter {
          &mut self.emit
      }
      fn some_property(&self) -> bool {
          self.emit2.borrow_mut().some_property_changed();
          self.some_property
      }
      fn set_some_property(&mut self, value: bool) {
          self.some_property = value;
          self.emit.some_property_changed();
      }
  }
-------------------

OBSERVED RESULT
The above (and attached) example compiles fine in Rust, even though it contains
an emit() statement in SomeQtObject::some_property(&self). If on the QML (or
C++) side a call to SomeQtObject::set_some_property(&mut self, value: bool) is
connected to this signal, undefined behaviour is invoked, as (implicitly) &self
gets transmuted into &mut self.

EXPECTED RESULT
The safe API of the rust-qt-binding-generator should ideally make such a
construct impossible.

ADDITIONAL INFORMATION
This might be related to https://bugs.kde.org/show_bug.cgi?id=406178, but I
think it's a different issue.

I've been thinking a bit on how to possibly solve this, but it's a non-trivial
issue that might not be solvable without API or behaviour changes...
The best option I see would be to internally create QueuedConnections on the
QObject that delay the update notifications and therefore ensure that there
will be no Rust -> C++ -> Rust call stacks on the same object. (That would also
fix #406178.)

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to