-
Notifications
You must be signed in to change notification settings - Fork 8
Valuable::Replace #1557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Valuable::Replace #1557
Conversation
| } | ||
| else if (impl->getTypeSize() <= getAllocSize()) | ||
| { | ||
| Replace(std::move(*impl)); | ||
| } | ||
| else { | ||
| IMPLEMENT | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple unimplemented code sections with IMPLEMENT macros:
else if (impl->getTypeSize() <= getAllocSize())
{
Replace(std::move(*impl));
}
else {
IMPLEMENT
}There are numerous unimplemented code sections marked with IMPLEMENT macros throughout the codebase, including in the new Become(encapsulated_instance&&) method. These macros throw exceptions when reached, which could lead to unexpected runtime failures.
Recommendation: Implement these sections properly before merging, or add detailed TODO comments explaining the expected behavior and when implementation will be completed.
| if (newRadicand.IsPrincipalSurd()) | ||
| break; | ||
| else { | ||
| update1(newRadicand); | ||
| update2(_2.shr()); | ||
| // FIXME : update1(newRadicand); // should work too (Exponentiation_test) | ||
| // FIXME : update2(_2.shr()); | ||
| update1(std::move(newRadicand)); | ||
| update2(std::move(_2.shr())); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code optimization concerns in multiple files:
- In
PrincipalSurd.cpp, there are commented out FIXME sections with alternative implementations:
// FIXME : update1(newRadicand); // should work too (Exponentiation_test)
// FIXME : update2(_2.shr());
update1(std::move(newRadicand));
update2(std::move(_2.shr()));- In
Sum.cpp, complex expressions were broken down into multiple statements:
Become((e.getBase() ^ f.getNumerator()) - ((-(*this - member)) ^ f.getDenominator()));Changed to:
auto baseExpNum = e.getBase() ^ f.getNumerator();
auto memMinThis = member - *this;
auto balancedNewValue = baseExpNum - (memMinThis ^ f.getDenominator());
Become(std::move(balancedNewValue));While breaking down complex expressions improves readability, the commented FIXME sections and lack of documentation explaining the optimization rationale make it difficult to understand the intended behavior and verify correctness.
Recommendation: Add clear documentation explaining the optimization changes and remove or address the FIXME comments before merging.
| LOG_AND_IMPLEMENT("New for " << *this) | ||
| } | ||
|
|
||
| void Valuable::Replace(Valuable&& obj) { | ||
| clone_on_write(); | ||
| auto sizeWas = getAllocSize(); | ||
| auto newSize = obj.getTypeSize(); | ||
| auto hashWas = obj.Hash(); | ||
| auto newWasView = this->GetView(); | ||
| assert(sizeWas >= newSize); | ||
| assert(DefaultAllocSize >= newSize && "Increase DefaultAllocSize"); | ||
| char buf[DefaultAllocSize]; | ||
| obj.New(buf, std::move(obj)); | ||
| Valuable& bufv = *reinterpret_cast<Valuable*>(buf); | ||
| this->~Valuable(); | ||
| bufv.New(this, std::move(bufv)); | ||
| setAllocSize(sizeWas); | ||
| if (Hash() != hashWas) { | ||
| LOG_AND_IMPLEMENT("Hash mismatch in Become for " << *this) | ||
| } | ||
| SetView(newWasView); | ||
| optimize(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Memory Safety Concerns in Valuable::Replace Method
The new Replace method implementation has potential memory safety issues:
void Valuable::Replace(Valuable&& obj) {
clone_on_write();
auto sizeWas = getAllocSize();
auto newSize = obj.getTypeSize();
auto hashWas = obj.Hash();
auto newWasView = this->GetView();
assert(sizeWas >= newSize);
assert(DefaultAllocSize >= newSize && "Increase DefaultAllocSize");
char buf[DefaultAllocSize];
obj.New(buf, std::move(obj));
Valuable& bufv = *reinterpret_cast<Valuable*>(buf);
this->~Valuable();
bufv.New(this, std::move(bufv));
setAllocSize(sizeWas);
if (Hash() != hashWas) {
LOG_AND_IMPLEMENT("Hash mismatch in Become for " << *this)
}
SetView(newWasView);
optimize();
}This pattern of using a fixed-size buffer (DefaultAllocSize) for temporary storage during object replacement relies on runtime assertions rather than compile-time guarantees. While there are assertion checks, these are only active in debug builds and don't prevent potential buffer overflows in release builds if object sizes exceed DefaultAllocSize.
Recommendations:
- Consider using dynamic memory allocation for the temporary buffer
- Add compile-time size checks where possible
- Document the size constraints and assumptions clearly
- Consider adding a size parameter to the
Newmethod to enable safer buffer management
| #endif | ||
| } | ||
|
|
||
| Valuable& Valuable::Become(int integer) { | ||
| Become(std::static_pointer_cast<Valuable>(std::make_shared<Integer>(integer))); | ||
| return *this; | ||
| } | ||
|
|
||
| void Valuable::Become(encapsulated_instance&& impl) { | ||
| while (impl->exp) { | ||
| impl = std::move(impl->exp); | ||
| } | ||
| auto h = impl->Hash(); | ||
| clone_on_write(); | ||
| auto isEncapsulatedInstance = Is<Valuable>(); | ||
| if (exp | ||
| || isEncapsulatedInstance | ||
| || impl->getTypeSize() > getAllocSize() | ||
| ) | ||
| { | ||
| if (isEncapsulatedInstance) { | ||
| DispatchDispose(std::move(exp)); | ||
| exp = std::move(impl); | ||
| } else { | ||
| auto allocSize = getAllocSize(); | ||
| this->~Valuable(); | ||
| new (this) Valuable(std::move(impl)); | ||
| setAllocSize(allocSize); | ||
| } | ||
| if (Hash() != h) { | ||
| LOG_AND_IMPLEMENT("Hash mismatch in Become for " << *this) | ||
| } | ||
| } | ||
| else if (impl->getTypeSize() <= getAllocSize()) | ||
| { | ||
| Replace(std::move(*impl)); | ||
| } | ||
| else { | ||
| IMPLEMENT | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unimplemented Code Sections with IMPLEMENT Macros
There are numerous unimplemented code sections marked with IMPLEMENT macros throughout the codebase, including in the new Become(encapsulated_instance&&) method:
void Valuable::Become(encapsulated_instance&& impl) {
while (impl->exp) {
impl = std::move(impl->exp);
}
auto h = impl->Hash();
clone_on_write();
auto isEncapsulatedInstance = Is<Valuable>();
if (exp
|| isEncapsulatedInstance
|| impl->getTypeSize() > getAllocSize()
)
{
if (isEncapsulatedInstance) {
DispatchDispose(std::move(exp));
exp = std::move(impl);
} else {
auto allocSize = getAllocSize();
this->~Valuable();
new (this) Valuable(std::move(impl));
setAllocSize(allocSize);
}
if (Hash() != h) {
LOG_AND_IMPLEMENT("Hash mismatch in Become for " << *this)
}
}
else if (impl->getTypeSize() <= getAllocSize())
{
Replace(std::move(*impl));
}
else {
IMPLEMENT
}
}The IMPLEMENT macro throws exceptions when reached, which could lead to unexpected runtime failures. This is particularly concerning in a method that handles memory management and object state transitions.
Recommendations:
- Implement the missing code sections before merging
- If implementation is deferred, add detailed TODO comments explaining the expected behavior and when implementation will be completed
- Consider adding fallback behavior for unimplemented sections rather than throwing exceptions
- Add tests that verify the implemented paths work correctly
| if (newRadicand.IsPrincipalSurd()) | ||
| break; | ||
| else { | ||
| update1(newRadicand); | ||
| update2(_2.shr()); | ||
| // FIXME : update1(newRadicand); // should work too (Exponentiation_test) | ||
| // FIXME : update2(_2.shr()); | ||
| update1(std::move(newRadicand)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Optimization Concerns in Multiple Files
There are several optimization-related issues across the changed files:
- In
PrincipalSurd.cpp, there are commented out FIXME sections with alternative implementations:
// FIXME : update1(newRadicand); // should work too (Exponentiation_test)
// FIXME : update2(_2.shr());
update1(std::move(newRadicand));
update2(std::move(_2.shr()));The commented FIXME sections suggest uncertainty about the correctness of the implementation. The change from direct parameter passing to using std::move could have performance implications, but it's unclear if this has been thoroughly tested.
- In
Sum.cpp, complex expressions were broken down into multiple statements:
// Original:
Become((e.getBase() ^ f.getNumerator()) - ((-(*this - member)) ^ f.getDenominator()));
// Changed to:
auto baseExpNum = e.getBase() ^ f.getNumerator();
auto memMinThis = member - *this;
auto balancedNewValue = baseExpNum - (memMinThis ^ f.getDenominator());
Become(std::move(balancedNewValue));While breaking down complex expressions improves readability, the lack of documentation explaining the optimization rationale makes it difficult to understand the intended behavior and verify correctness.
Recommendations:
- Remove or address the FIXME comments before merging
- Add clear documentation explaining the optimization changes and their rationale
- Include test cases that verify the optimized code paths work correctly
- Consider adding performance benchmarks to validate optimization improvements
5a2d548 to
aad5dc1
Compare
| LOG_AND_IMPLEMENT("New for " << *this) | ||
| } | ||
|
|
||
| void Valuable::Replace(Valuable&& obj) { | ||
| clone_on_write(); | ||
| auto sizeWas = getAllocSize(); | ||
| auto newSize = obj.getTypeSize(); | ||
| auto hashWas = obj.Hash(); | ||
| auto newWasView = this->GetView(); | ||
| assert(sizeWas >= newSize); | ||
| assert(DefaultAllocSize >= newSize && "Increase DefaultAllocSize"); | ||
| char buf[DefaultAllocSize]; | ||
| obj.New(buf, std::move(obj)); | ||
| Valuable& bufv = *reinterpret_cast<Valuable*>(buf); | ||
| this->~Valuable(); | ||
| bufv.New(this, std::move(bufv)); | ||
| setAllocSize(sizeWas); | ||
| if (Hash() != hashWas) { | ||
| LOG_AND_IMPLEMENT("Hash mismatch in Become for " << *this) | ||
| } | ||
| SetView(newWasView); | ||
| optimize(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Memory Safety Concerns in Valuable::Replace Method
The new Replace method implementation has potential memory safety issues:
void Valuable::Replace(Valuable&& obj) {
clone_on_write();
auto sizeWas = getAllocSize();
auto newSize = obj.getTypeSize();
auto hashWas = obj.Hash();
auto newWasView = this->GetView();
assert(sizeWas >= newSize);
assert(DefaultAllocSize >= newSize && "Increase DefaultAllocSize");
char buf[DefaultAllocSize];
obj.New(buf, std::move(obj));
Valuable& bufv = *reinterpret_cast<Valuable*>(buf);
this->~Valuable();
bufv.New(this, std::move(bufv));
setAllocSize(sizeWas);
// ...
}This pattern of using a fixed-size buffer (DefaultAllocSize) for temporary storage during object replacement relies on runtime assertions rather than compile-time guarantees. While there are assertion checks, these are only active in debug builds and don't prevent potential buffer overflows in release builds if object sizes exceed DefaultAllocSize.
Recommendations:
- Consider using dynamic memory allocation for the temporary buffer
- Add compile-time size checks where possible
- Document the size constraints and assumptions clearly
- Consider adding a size parameter to the
Newmethod to enable safer buffer management
| #endif | ||
| } | ||
|
|
||
| Valuable& Valuable::Become(int integer) { | ||
| Become(std::static_pointer_cast<Valuable>(std::make_shared<Integer>(integer))); | ||
| return *this; | ||
| } | ||
|
|
||
| void Valuable::Become(encapsulated_instance&& impl) { | ||
| while (impl->exp) { | ||
| impl = std::move(impl->exp); | ||
| } | ||
| auto h = impl->Hash(); | ||
| clone_on_write(); | ||
| auto isEncapsulatedInstance = Is<Valuable>(); | ||
| if (exp | ||
| || isEncapsulatedInstance | ||
| || impl->getTypeSize() > getAllocSize() | ||
| ) | ||
| { | ||
| if (isEncapsulatedInstance) { | ||
| DispatchDispose(std::move(exp)); | ||
| exp = std::move(impl); | ||
| } else { | ||
| auto allocSize = getAllocSize(); | ||
| this->~Valuable(); | ||
| new (this) Valuable(std::move(impl)); | ||
| setAllocSize(allocSize); | ||
| } | ||
| if (Hash() != h) { | ||
| LOG_AND_IMPLEMENT("Hash mismatch in Become for " << *this) | ||
| } | ||
| } | ||
| else if (impl->getTypeSize() <= getAllocSize()) | ||
| { | ||
| Replace(std::move(*impl)); | ||
| } | ||
| else { | ||
| IMPLEMENT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unimplemented Code Sections with IMPLEMENT Macros
There are unimplemented code sections marked with IMPLEMENT macros in the new Become(encapsulated_instance&&) method:
void Valuable::Become(encapsulated_instance&& impl) {
// ...
else if (impl->getTypeSize() <= getAllocSize())
{
Replace(std::move(*impl));
}
else {
IMPLEMENT
}
}The IMPLEMENT macro throws exceptions when reached, which could lead to unexpected runtime failures. This is particularly concerning in a method that handles memory management and object state transitions.
Recommendations:
- Implement the missing code sections before merging
- If implementation is deferred, add detailed TODO comments explaining the expected behavior and when implementation will be completed
- Consider adding fallback behavior for unimplemented sections rather than throwing exceptions
- Add tests that verify the implemented paths work correctly
| if (newRadicand.IsPrincipalSurd()) | ||
| break; | ||
| else { | ||
| update1(newRadicand); | ||
| update2(_2.shr()); | ||
| // FIXME : update1(newRadicand); // should work too (Exponentiation_test) | ||
| // FIXME : update2(_2.shr()); | ||
| update1(std::move(newRadicand)); | ||
| update2(std::move(_2.shr())); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Optimization Concerns in Multiple Files
There are several optimization-related issues across the changed files:
- In
PrincipalSurd.cpp, there are commented out FIXME sections with alternative implementations:
// FIXME : update1(newRadicand); // should work too (Exponentiation_test)
// FIXME : update2(_2.shr());
update1(std::move(newRadicand));
update2(std::move(_2.shr()));The commented FIXME sections suggest uncertainty about the correctness of the implementation. The change from direct parameter passing to using std::move could have performance implications, but it's unclear if this has been thoroughly tested.
- In
Sum.cpp, complex expressions were broken down into multiple statements without clear documentation:
// Original:
Become((e.getBase() ^ f.getNumerator()) - ((-(*this - member)) ^ f.getDenominator()));
// Changed to:
auto baseExpNum = e.getBase() ^ f.getNumerator();
auto memMinThis = member - *this;
auto balancedNewValue = baseExpNum - (memMinThis ^ f.getDenominator());
Become(std::move(balancedNewValue));Recommendations:
- Remove or address the FIXME comments before merging
- Add clear documentation explaining the optimization changes and their rationale
- Include test cases that verify the optimized code paths work correctly
- Consider adding performance benchmarks to validate optimization improvements
No description provided.