Submitter: Martin Sebor
Document Number: N2193
Submission Date: November 8, 2017
Subject: effects of mtx_destroy on an uninitialized mutex

Summary

§7.26.4.3 The mtx_destroy function contains the following text:

Description

-2- The mtx_destroy function releases any resources used by the mutex pointed to by mtx. No threads can be blocked waiting for the mutex pointed to by mtx.

Returns

-3- The mtx_destroy function returns no value.

This inadequate specification has precipitated a number of questions including the following raised by DR 493:

  1. What is the behavior of mtx_destroy() when called with a pointer to an object initialized to all zeros (such as a mutex object with static storage duration) that has not been passed to mtx_init()? (This is important because it might mean that programs need to associate an external flag with each mutex object indicating whether or not it has been initialized in a way that requires mtx_destroy() to be called on it.)
  2. What is the behavior of the function when called with the same pointer more than once? Is it required to have no effect or is it undefined?
  3. … (question covered by DR 469.)
  4. What state is a mutex object in after mtx_destroy() has been called with it as an argument? Can such an object be subsequently passed as argument to any of the other mutex functions? For example, can such a mutex object be safely passed to mtx_init()? To any of the other mutex functions such as mtx_lock() and, if so, with what effects? (Undefined or error?)

The committee's response is that:

  1. It is undefined behavior to call mtx_destroy() with a pointer to an object that has not been initialized by a call to mtx_init(). In §7.26.4.1 p2 the editor should consider changing "can" to "shall".
  2. It is undefined behavior to call mtx_destroy() with a pointer to an object that has not been initialized by a call to mtx_init(), so calling it twice without an intervening mtx_init results in undefined behavior.
  3. … (answer points to DR 469.)
  4. The memory that had been used as an mtx_t object has indeterminate value. Undefined behavior results if it is subsequently used as an argument to other mtx functions other than mtx_init.

This response, while reasonable, is not supported by the standard.

First, there is no mention of undefined behavior anywhere in §7.26. Furthermore, there are no references to the section in the informative §J.2 Undefined behavior that collects references to instances of undefined behavior in the standard. Therefore, the only possible interpretation is that the behavior is unspecified (although there are no references to in §7.26. in §J.1 Unspecified behavior either). Failing to specify the behavior in these basic conditions makes it impossible to write strictly conforming or portable programs, thus defeating the purpose of the standard.

To reflect the committee's response the standard must be changed and each instance of the undefined behavior must be cpatured.

Suggested Change

Modify §7.26.4.3 The mtx_destroy function as follows:

Description

-2- The mtx_destroy function shall destroy releases any resources used by the mutex object pointed to by mtx. The mutex shall have been initialized by a prior call to mtx_init. The mutex shall not be locked or in use by any other thread.No threads can be blocked waiting for the mutex pointed to by mtx.

-3- A destroyed mutex has an indeterminate value and is effectively uninitialized. It can be initialized by a call to mtx_init. The effects of using a destroyed mutex object otherwise are undefined.

Note that the specification for the mtx_init function doesn't refer to any resources so specifying that mtx_destroy releases some ressources is meaningless.

Also note that specifying that no threads shall be blocked on the mutex is an insufficient precondition. A necessary precondition is that the mutex not be locked (including by the current thread in the case of recursive mutexes) or being used by other threads as an argument to a call to any threads functions.

In addition, add a bullet to §J.2 Undefined behavior referencing the undefined behavior that results from violating the shall requirements outlined in the paragraph above.