aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/c
diff options
context:
space:
mode:
authorGravatar James Keeling <jtkeeling@google.com>2018-07-24 09:51:13 -0700
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2018-07-24 09:57:12 -0700
commita45ffbd9b5c7d8fdaae6e41432f916639bdbe305 (patch)
treeda13772f02b54c6392294a74d9b6d8761ecde980 /tensorflow/c
parent568727eed199dba04e37f500265b50f96fed455e (diff)
Allow TF_Delete* functions to accept nullptr
The TF_Delete* functions in TensorFlow's C API now safely do nothing when asked to delete a null pointer. This mirrors the behaviour of free in C and delete in C++. PiperOrigin-RevId: 205844191
Diffstat (limited to 'tensorflow/c')
-rw-r--r--tensorflow/c/c_api.cc5
-rw-r--r--tensorflow/c/c_api.h1
-rw-r--r--tensorflow/c/c_api_test.cc23
3 files changed, 29 insertions, 0 deletions
diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc
index 1b937883c8..f516ce4f18 100644
--- a/tensorflow/c/c_api.cc
+++ b/tensorflow/c/c_api.cc
@@ -328,6 +328,7 @@ TF_Buffer* TF_NewBufferFromString(const void* proto, size_t proto_len) {
}
void TF_DeleteBuffer(TF_Buffer* buffer) {
+ if (buffer == nullptr) return;
if (buffer->data_deallocator != nullptr) {
(*buffer->data_deallocator)(const_cast<void*>(buffer->data),
buffer->length);
@@ -357,6 +358,7 @@ void TF_CloseDeprecatedSession(TF_DeprecatedSession* s, TF_Status* status) {
void TF_DeleteDeprecatedSession(TF_DeprecatedSession* s, TF_Status* status) {
status->status = Status::OK();
+ if (s == nullptr) return;
delete s->session;
delete s;
}
@@ -907,6 +909,7 @@ TF_Library* TF_LoadLibrary(const char* library_filename, TF_Status* status) {
TF_Buffer TF_GetOpList(TF_Library* lib_handle) { return lib_handle->op_list; }
void TF_DeleteLibraryHandle(TF_Library* lib_handle) {
+ if (lib_handle == nullptr) return;
tensorflow::port::Free(const_cast<void*>(lib_handle->op_list.data));
delete lib_handle;
}
@@ -1854,6 +1857,7 @@ TF_Graph::TF_Graph()
TF_Graph* TF_NewGraph() { return new TF_Graph; }
void TF_DeleteGraph(TF_Graph* g) {
+ if (g == nullptr) return;
g->mu.lock();
g->delete_requested = true;
const bool del = g->sessions.empty();
@@ -2529,6 +2533,7 @@ void TF_CloseSession(TF_Session* s, TF_Status* status) {
void TF_DeleteSession(TF_Session* s, TF_Status* status) {
status->status = Status::OK();
+ if (s == nullptr) return;
TF_Graph* const graph = s->graph;
if (graph != nullptr) {
graph->mu.lock();
diff --git a/tensorflow/c/c_api.h b/tensorflow/c/c_api.h
index c5035e0e41..c8ae6f2dd1 100644
--- a/tensorflow/c/c_api.h
+++ b/tensorflow/c/c_api.h
@@ -44,6 +44,7 @@ limitations under the License.
// * size_t is used to represent byte sizes of objects that are
// materialized in the address space of the calling process.
// * int is used as an index into arrays.
+// * Deletion functions are safe to call on nullptr.
//
// Questions left to address:
// * Might at some point need a way for callers to provide their own Env.
diff --git a/tensorflow/c/c_api_test.cc b/tensorflow/c/c_api_test.cc
index c470ab5649..e674b1623c 100644
--- a/tensorflow/c/c_api_test.cc
+++ b/tensorflow/c/c_api_test.cc
@@ -1426,6 +1426,29 @@ TEST(CAPI, SavedModelNullArgsAreValid) {
TF_DeleteStatus(s);
}
+TEST(CAPI, DeletingNullPointerIsSafe) {
+ TF_Status* status = TF_NewStatus();
+
+ TF_DeleteStatus(nullptr);
+ TF_DeleteBuffer(nullptr);
+ TF_DeleteTensor(nullptr);
+ TF_DeleteSessionOptions(nullptr);
+ TF_DeleteGraph(nullptr);
+ TF_DeleteImportGraphDefOptions(nullptr);
+ TF_DeleteImportGraphDefResults(nullptr);
+ TF_DeleteFunction(nullptr);
+ TF_DeleteSession(nullptr, status);
+ EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeletePRunHandle(nullptr);
+ TF_DeleteDeprecatedSession(nullptr, status);
+ EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteDeviceList(nullptr);
+ TF_DeleteLibraryHandle(nullptr);
+ TF_DeleteApiDefMap(nullptr);
+
+ TF_DeleteStatus(status);
+}
+
REGISTER_OP("TestOpWithNoGradient")
.Input("x: T")
.Output("y: T")