Skip to content
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

Introduce Bstr scoped guard class to manage BSTR string type #8004

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

dreamer-dead
Copy link
Contributor

@dreamer-dead dreamer-dead commented Apr 25, 2023

This is related to #8003
At the moment I'm trying to add scoped class for BSTR string type to support automatic string memory management.

Now Bstr class has a minimal set of methods/operators that allow to use it in the code.
Operators set could be expanded, for example operator&() can be added or some other convenient helpers.
But it can handle the BSTR memory and correctly deallocate it.

Added few tests and tied to demonstrate how it can be used.

Please, take a look. Looking forward to discuss this PR

@dreamer-dead dreamer-dead requested review from a team as code owners April 25, 2023 09:54
@dreamer-dead dreamer-dead changed the title [WIP] Raii 8003 bstr [WIP] Introduce Bstr scoped guard class to manage BSTR string type Apr 25, 2023
@dreamer-dead dreamer-dead changed the title [WIP] Introduce Bstr scoped guard class to manage BSTR string type Introduce Bstr scoped guard class to manage BSTR string type Apr 25, 2023
static Bstr fromString(std::wstring_view);

Bstr() = default;
~Bstr();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Destructor and other methods that don't throw exceptions could be marked with noexcept keyword

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add noexcept specifier for few method.
Also IIRC, the destructor is always has implicit noexcept spec by default
https://en.cppreference.com/w/cpp/language/noexcept_spec
[destructors](https://en.cppreference.com/w/cpp/language/destructor) unless the destructor of any potentially-constructed base or member is potentially-throwing (see below)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also IIRC, the destructor is always has implicit noexcept spec by default

Thanks for sharing this! I was not aware of it. I agree that adding noexcept to other methods would be beneficial.

return !!bstr_;
}

BSTR get() const {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A copy to the raw BSTR pointer is returned here (pointer to raw BSTR data), it should return const BSTR instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify why const should be added?
const BSTR is just a WCHAR* const type and in my opinion adding const does not affect anything here.
It will be possible to store const BSTR result into BSTR bs variable, see https://godbolt.org/z/v74cvjbxz

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please clarify why const should be added?

I agree that BSTR string can be modified since BSTR is a pointer to a wide-character string, the const qualifier applies to the pointer itself and not the data it points to. The data can still be modified. The const on the return type here is mostly to tell the compiler BSTR that's returned will not be modified (or rather, should not be modified) by the callers. This might not apply here, but when dealing with getters I think it is always good to set the contract upfront and just use const whenever we expect the returned data should not change (return type could be something different in the future and not a pointer)

}

BSTR* Bstr::receiveAddress() {
assert(!bstr_);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comment on assert usage. Also, I'm not a big fan of adding asserts on production code, I'd prefer to return gracefully if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main reason to add this assert is to prevent memory leak and to ensure that the Bstr::bstr_ pointer is null and does not hold any BSTR buffer allocated earlier.
Consider the following scenario:

Bstr bs = Bstr:: fromString(L"foo");
GetFileTime(..., bs.receiveAddress()); // for Debug builds assert can signal here

I personally like the idea of some kind of debug macro helpers with a well defined behaviour like DCHECK and I wasn't sure what to use in this project.
Another approach is to free the buffer every time receiveAddress is called.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good, thanks for the explanation! You can add this information to a code comment

Copy link
Contributor

@marcosd4h marcosd4h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good! I've made few comments and questions on potential things to improve

@mike-myers-tob mike-myers-tob added ready for review Pull requests that are ready to be reviewed by a maintainer refactor Related to osquery code refactoring labels May 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
development ready for review Pull requests that are ready to be reviewed by a maintainer refactor Related to osquery code refactoring Windows
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants