Secure way to create a getter for a char[ ] field - c++

So im doing an assignment and i have to use a C-style string as a field of my class. I'm trying to create a secure getter for it but i have no idea how to do it.
Field im using:
char name[20];
So far i tried these things:
char* Car::getName() {
return &name[0];
}
^ the only one that works but if im right it returns the address of the field which allows to edit it.
char* Car::getName() {
char ret[20];
strcpy(ret, name);
return ret;
}
^another approach i tried with no success
So I'd like to ask what's a proper way of creating such getter? (Sorry if its a naive question but i haven't used a lot of C in my life)

Declare the return type to be const char *, and make the function itself const (to indicate the object is unchanged by the call). Callers can ignore that through casts, but that's on them; this is for correctness, not security.
const char* Car::getName() const {
return &name[0];
}
They'll have a pointer to the class internals, but it's explicitly stated that said pointer is to read-only data.
Other options include exposing it as a std::string that you construct on demand (return std::string(name); with return type std::string), or returning a smart pointer of some kind to dynamically allocated memory (equivalent morally to returning std::string). Making a copy and returning a dumb pointer (e.g. return strdup(name);) is a bad idea, since now you've opened the door to memory leaks; the caller has to manually free/delete memory.

Related

How to return a const char * from a C/C++ function?

I have the following C++ function that reads a string from the flash memory and returns it.
I want to avoid using the String class because this is on an Arduino and I've been advised that the String class for the Arduino is buggy.
const char* readFromFlashMemory()
{
char s[FLASH_STOP_ADDR-FLASH_START_ADDR+2];
memset(s, (byte)'\0', FLASH_STOP_ADDR-FLASH_START_ADDR+2);
unsigned short int numChars = 0;
for (int i = FLASH_START_ADDRESS; i <= FLASH_STOP_ADDRESS; i++)
{
byte b = EEPROM.read(i);
if (b == (byte)'\0')
return s;
else
s[numChars++] = (char)b;
}
}
This function seems to work. But the calling method gets back an empty string.
Am I not allowed to return a pointer to a character array that is on this function's stack?
How is the best/most idiomatic way I should write this function so the calling function receives the value that I want to pass to it?
The comments are probably going to lead you astray or at best confuse you. Let me break it down with some options.
Firstly, the problem is as you say: the array whose address you are returning no longer exists when the function is popped off the stack to the caller. Ignoring this results in Undefined Behavior.
Here are a few options, along with some discussion:
The caller owns the buffer
void readFromFlashMemory(char *s, size_t len)
Advantage is that the caller chooses how this memory is allocated, which is useful in embedded environments.
Note you could also choose to return s from this function as a convenience, or to convey some extra meaning.
For me, if I was working in an embedded environment such as Arduino, this would be my preference 100%.
Use std::string, std::vector or similar
std::string readFromFlashMemory()
This is probably the way you'd do it if you didn't care about allocation overhead and other potential issues such as fragmentation over time.
Allocate memory yourself
char* readFromFlashMemory()
If you want to ensure the allocated memory is exactly the right size, then you'd probably read into a local buffer first, and then allocate the memory and copy. Same memory considerations as std::string or other solutions dealing with heap memory.
This form also has the nightmarish property of the caller being responsible for managing the returned pointer and eventually calling delete[]. It's highly inadvisable. It's also distressingly common. :(
Better way to return dynamically allocated memory, if you absolutely must
std::unique_ptr<char[]> readFromFlashMemory()
Same as #3, but the pointer is managed safely. Requires C++11 or later.
Use a static buffer
const char* readFromFlashMemory()
{
static char s[FLASH_STOP_ADDR-FLASH_START_ADDR+2];
// ...
return s;
}
Generally frowned upon. Particularly because this type of pattern results in nasty problems in multi-threaded environments.
People mostly choose this approach because they're lazy and want a simple interface. I guess one benefit is that the caller doesn't have to know anything about what size buffer is acceptable.
Make your own class with an internal buffer
class FlashReader
{
public:
const char* Read();
private:
char buffer[FLASH_STOP_ADDR-FLASH_START_ADDR+2];
};
This is more of a verbose solution, and may start to smell like over-engineering. But it does combine the best parts of both #1 and #5. That is, you get stack allocation of your buffer, you don't need to know the size, and the function itself doesn't need extra arguments.
If you did want to have a static buffer, then you could just define one static instance of the class, but the difference would be a clear intent of this in the code.

Construct a string without allocation

Considering we have a struct with char * member, if we want to request the content of this member, we normally do
char const * get_member() { return object.member; }
By this, we only return a pointer, without any allocation.
If now we want to return a string; is it possible to let the string just use that pointer, instead of copying the content and construct a new string object?
string const & get_member() { return object.member; }
will this code above will do a memory allocation. what like of extra work will this method do compare to the char const * one?
No, it is not possible. std::string always allocates its own memory and cannot take ownership of a pre-existing buffer.
You can either return a copy of the pointer, or you can use a std::string member in the first place, and return a reference to it. Or, alternatively return std::string_view which can be used with either char* or a std::string member. String view is only available since C++17 but it also exists in standard library extensions some for earlier compilers and there also exists non-standard implementations.
The struct is from some C code based library, just want to wrap with C++, at the mean time, do not kill any performance.
Then it seems that returning a std::string would not be an appropriate design.

How to return char* from class?

I want to return a name, and while the main should be able to alter it (in main's scope), it should not change in the class.
If I do it like this:
char* get_name(){
char* name = new char[sizeof(_name)+1];
strcpy(_name,name);
return name;
}
do I have to delete[] at some point? And when?
Edit: I don't believe it's the same problem as pointer to local variable since the problem here is how to delete it after i use it.
Well, that's the problem with manual memory management. Indeed, if you want to return a copy, then it would be the caller's responsibility to free the memory, which is extremely error prone. That's why C++ has std::string class which handles the memory;
std::string get_name() const //note the const on member function
{
return _name; //this will work even if _name is char*, btw
}
As others have said, using std::string is probably a better option. If you want to use a char* instead, I would suggest simply returning a const char*:
const char* get_name() {
return _name;
}
You will be returning a const reference, meaning that the calling code should not change it. The way you are doing it, you will indeed have to delete after every call to get_name(), which is not ideal.
You will indeed have to delete[] the returned pointer at some point: since every new[] must be balanced with a delete[]. That can be difficult to manage.
But why not maintain a std::string member in your class, and write
const std::string& getName() const
{
return name; // name is the class member.
}
instead? Returning a const reference obviates a deep copy and also means the caller cannot modify the member.
First of all I think you mean
strcpy( name, _name );
^^^^^^^^^^^
instead of
strcpy( _name, name );
^^^^^^^^^^^
The object of the class that returns the pointer to the dynamically allocated memory will not have access to this memory after returning the pointer.
So it is the client of the function who shall free the allocated memory.
As other already pointed it is better to use standard class std::string in such cases.

Handle a char array returned from a function in C

I am using a library called tinyXML, which parses XML files. Many of its methods return a const char*.
After having read this question:
how to return a char array from a function in C
I now believe that every time a method returns a char* it is the caller's (my) responsibility to explicitly free it, because it is probably allocated dynamically on the heap. Am I right / wrong? What can I assume?
(If I ever wrote a library I would much rather return std::string instead of char* arrays, because they are so much simpler for the user.)
You can't assume anything and must check the documentation for the method you are calling to know if you must free the pointer or not. Sometimes a function returning a const char * might be returning a statically allocated string:
const char *getName(){
return "SPQR3";
}
Or it might be a pointer that is someone else's responsibility to free. For example, strcpy's return value is the same as the pointer you pass to it as input.
Read the library's documentation. Both usages (pointer to an internal buffer, or pointer to a dynamically-allocated buffer) are common, and aren't distinguishable from the function prototype alone.

const object and const constructor

Is there any way to know if an object is a const object or regular object, for instance consider the following class
class String
{
String(const char* str);
};
if user create a const object from String then there is no reason to copy the passed native string and that because he will not make any manipulation on it, the only thing he will do is get string size, string search and other functions that will not change the string.
There is a very good reason for copying - you can't know that the lifetime of the const char * is the same as that of the String object. And no, there is no way of knowing that you are constructing a const object.
Unfortunately, C++ does not provide a way to do what you are attempting. Simply passing a const char * does not guarantee the lifetime of the memory being pointed to. Consider:
char * a = new char[10];
char const *b = a;
String c (b);
delete[] a;
// c is now broken
There is no way for you to know. You could write a class that tightly interacts with String and that creates a constant string pointing to an external buffer (by making the corresponding constructor private and making the interacting class a nested class or a friend of String).
If all you worry about is doing dynamic memory management on a potentially small constant string, you can implement the Small String Optimization (also Small Object/Buffer Optimization). It works by having an embedded buffer in your string class, and copying each string up to some predefined size into that buffer, and each string that's larger to a dynamically allocated storage (the same technique is used by boost::function for storing small sized function objects).
class String {
union {
char *dynamicptr;
char buffer[16];
};
bool isDynamic;
};
There are clever techniques for storing even the length of the embedded string into the buffer itself (storing its length as buffer[15] and similar trickeries).
You could use const_string to do what you're looking for. However, even with const string you have to "tell" it that the string doesn't need to be copied.
const char* foo = "c-string";
boost::const_string bar(foo); // will copy foo
boost::const_string baz(boost::ref(foo)); // assumes foo will always be a valid pointer.
if user create a const object from String then there is no reason to copy the passed native string and that because he will not make any manipulation on it, the only thing he will do is get string size, string search and other functions that will not change the string.
Oh yes there is. Just that it is passes as const doesn't mean that it actually is const outside of the constructor call, and it especially doesn't mean it won't be destroyed while the string object still exists. The keyword const for a function argument only means that the function won't modify or delete it (trying to implement a function that modifies a const argument will result in a compiler error), but there's no way for the function to know what happens outside.
What you're looking for is basically a COW (copy on write) string. Such things are entirely possible, but getting them to work well is somewhat non-trivial. In a multithreaded environment, getting good performance can go beyond non-trivial into the decidedly difficult range.