Is it legal/safe to cast away `const` for a heap-allocated object?

淺唱寂寞╮ 提交于 2020-01-30 02:30:11

问题


My use case is as follows.

I develop a library in which some loaded plugins can create objects (allocated using malloc() by the library), and some other plugins can read properties of those objects but not modify them.

For me this is a case of having a non-const API for the creating/writer side and a const API for the reader side, for example:

// writer API
struct obj *obj_create(void);
void obj_set_some_property(struct obj *obj, int property);

// reader API
int obj_get_some_property(const struct obj *obj);

The library casts a struct obj * (created by the writer side) to a const struct obj * (available to the reader side).

My problem is that those objects also have reference counts, and the reader side can call your typical reference count incrementation/decrementation functions. Those functions need to modify the object.

My question is: in this specific context, is it safe for the reference count incrementation/decrementation functions to accept a const struct obj * and cast away the const internally? Note that the reference count decrementation function could also destroy (free) the object if the count reaches zero.

I know that §6.7.3¶5 says:

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.

I just can't figure out what defined with a const-qualified type means. Does this apply if my object is heap-allocated? I totally understand why it would be UB to do so with a literal string pointer (.rodata), for example. But what if the object is created to be non-const in the beginning?

strchr() is a well known example of casting const away: it accepts const char * and returns char *, which points within the const char * parameter. How is this legal considering §6.7.3¶5?


回答1:


In this context, defined refers to the program statement defining the variable, such as const struct obj x = {};. This is as opposed to a statement merely declaring it, such as const struct obj* x;.

In C, memory returned by malloc is uninitialized storage that can be safely written to. In fact, your library must have done this at least once before passing the structure to the client!

In theory, you might have a problem if the client somehow declared a const obj x = OBJ_INITIALIZER; and then passed it to your library. Your compiler might have stuck that variable definition into a read-only page of memory, or might optimize too aggressively on the assumption that it can never be modified. So you would need to specify that any library function that casts away const internally works only on objects from its own factories.

One way to ensure that untrusted client code can’t violate this assumption is to pass in handles rather than object pointers, but your library might not need to bother.

You might also conceivably run into problems if the client code uses the fields you modify, and if the compiler assumes that a function that takes a const struct obj* parameter cannot modify it through that parameter. You might work around that by returning a reference that aliases the object, which the compiler will not assume is the same unmodified object (or, I guess, by abusing volatile).

In C++, you would have the option of declaring the fields that need to be modified mutable.




回答2:


Objects allocated by malloc do not have any type, let alone a const-qualified one. It is fine to modify them regardless of whether you pointed to the object with a pointer-to-const at some stage.

"defined with a const-qualified type" requires that the object had a definition (malloc is a function call, not a definition).



来源:https://stackoverflow.com/questions/53568990/is-it-legal-safe-to-cast-away-const-for-a-heap-allocated-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!