1 /*********************                                                        */
2 /*! \file exception.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Tim King, Morgan Deters, Andres Noetzli
6  ** This file is part of the CVC4 project.
7  ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8  ** in the top-level source directory) and their institutional affiliations.
9  ** All rights reserved.  See the file COPYING in the top-level source
10  ** directory for licensing information.\endverbatim
11  **
12  ** \brief CVC4's exception base class and some associated utilities
13  **
14  ** CVC4's exception base class and some associated utilities.
15  **/
16 
17 #include "base/exception.h"
18 
19 #include <cstdarg>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <string>
24 
25 #include "base/cvc4_assert.h"
26 
27 using namespace std;
28 
29 namespace CVC4 {
30 
31 thread_local LastExceptionBuffer* LastExceptionBuffer::s_currentBuffer = NULL;
32 
LastExceptionBuffer()33 LastExceptionBuffer::LastExceptionBuffer() : d_contents(NULL) {}
34 
~LastExceptionBuffer()35 LastExceptionBuffer::~LastExceptionBuffer() {
36   if(d_contents != NULL){
37     free(d_contents);
38     d_contents = NULL;
39   }
40 }
41 
setContents(const char * string)42 void LastExceptionBuffer::setContents(const char* string) {
43   if(d_contents != NULL){
44     free(d_contents);
45     d_contents = NULL;
46   }
47 
48   if(string != NULL){
49     d_contents = strdup(string);
50   }
51 }
52 
53 const char* IllegalArgumentException::s_header = "Illegal argument detected";
54 
formatVariadic()55 std::string IllegalArgumentException::formatVariadic() {
56   return std::string();
57 }
58 
formatVariadic(const char * format,...)59 std::string IllegalArgumentException::formatVariadic(const char* format, ...) {
60   va_list args;
61   va_start(args, format);
62 
63   int n = 512;
64   char* buf = NULL;
65 
66   for (int i = 0; i < 2; ++i){
67     Assert(n > 0);
68     if(buf != NULL){
69       delete [] buf;
70     }
71     buf = new char[n];
72 
73     va_list args_copy;
74     va_copy(args_copy, args);
75     int size = vsnprintf(buf, n, format, args);
76     va_end(args_copy);
77 
78     if(size >= n){
79       buf[n-1] = '\0';
80       n = size + 1;
81     } else {
82       break;
83     }
84   }
85   // buf is not NULL is an invariant.
86   // buf is also 0 terminated.
87   Assert(buf != NULL);
88   std::string result(buf);
89   delete [] buf;
90   va_end(args);
91   return result;
92 }
93 
format_extra(const char * condStr,const char * argDesc)94 std::string IllegalArgumentException::format_extra(const char* condStr, const char* argDesc){
95   return ( std::string("`") + argDesc + "' is a bad argument"
96            + (*condStr == '\0' ? std::string() :
97               ( std::string("; expected ") +
98                 condStr + " to hold" )) );
99 }
100 
construct(const char * header,const char * extra,const char * function,const char * tail)101 void IllegalArgumentException::construct(const char* header, const char* extra,
102                                          const char* function, const char* tail) {
103   // try building the exception msg with a smallish buffer first,
104   // then with a larger one if sprintf tells us to.
105   int n = 512;
106   char* buf;
107 
108   for(;;) {
109     buf = new char[n];
110 
111     int size;
112     if(extra == NULL) {
113       size = snprintf(buf, n, "%s\n%s\n%s",
114                       header, function, tail);
115     } else {
116       size = snprintf(buf, n, "%s\n%s\n\n  %s\n%s",
117                       header, function, extra, tail);
118     }
119 
120     if(size < n) {
121       break;
122     } else {
123       // size >= n
124       // try again with a buffer that's large enough
125       n = size + 1;
126       delete [] buf;
127     }
128   }
129 
130   setMessage(string(buf));
131 
132 #ifdef CVC4_DEBUG
133   LastExceptionBuffer* buffer = LastExceptionBuffer::getCurrent();
134   if(buffer != NULL){
135     if(buffer->getContents() == NULL) {
136       buffer->setContents(buf);
137     }
138   }
139 #endif /* CVC4_DEBUG */
140   delete [] buf;
141 }
142 
construct(const char * header,const char * extra,const char * function)143 void IllegalArgumentException::construct(const char* header, const char* extra,
144                                          const char* function) {
145   // try building the exception msg with a smallish buffer first,
146   // then with a larger one if sprintf tells us to.
147   int n = 256;
148   char* buf;
149 
150   for(;;) {
151     buf = new char[n];
152 
153     int size;
154     if(extra == NULL) {
155       size = snprintf(buf, n, "%s.\n%s\n",
156                       header, function);
157     } else {
158       size = snprintf(buf, n, "%s.\n%s\n\n  %s\n",
159                       header, function, extra);
160     }
161 
162     if(size < n) {
163       break;
164     } else {
165       // try again with a buffer that's large enough
166       n = size + 1;
167       delete [] buf;
168     }
169   }
170 
171   setMessage(string(buf));
172 
173 #ifdef CVC4_DEBUG
174   LastExceptionBuffer* buffer = LastExceptionBuffer::getCurrent();
175   if(buffer != NULL){
176     if(buffer->getContents() == NULL) {
177       buffer->setContents(buf);
178     }
179   }
180 #endif /* CVC4_DEBUG */
181   delete [] buf;
182 }
183 
184 } /* namespace CVC4 */
185