annotate common.cpp @ 411:ad2206c24986 api-inversion

Fix a memory corruption bug. When allocating the adb_t in audiodb_open(), zero the memory; then we're not going to try to free() or delete some arbitrary uninitialized thing if the thing that we're opening turns out not to be an audiodb database.
author mas01cr
date Thu, 11 Dec 2008 08:54:06 +0000
parents 58b88ab69424
children 1e748d834e24
rev   line source
mas01cr@239 1 #include "audioDB.h"
mas01cr@392 2 extern "C" {
mas01cr@392 3 #include "audioDB_API.h"
mas01cr@402 4 #include "audioDB-internals.h"
mas01cr@392 5 }
mas01cr@239 6
mas01cr@239 7 #if defined(O2_DEBUG)
mas01cr@239 8 void sigterm_action(int signal, siginfo_t *info, void *context) {
mas01cr@239 9 exit(128+signal);
mas01cr@239 10 }
mas01cr@239 11
mas01cr@239 12 void sighup_action(int signal, siginfo_t *info, void *context) {
mas01cr@239 13 // FIXME: reread any configuration files
mas01cr@239 14 }
mas01cr@239 15 #endif
mas01cr@239 16
mas01cr@385 17 int acquire_lock(int fd, bool exclusive) {
mas01cr@239 18 struct flock lock;
mas01cr@239 19 int status;
mas01cr@239 20
mas01cr@239 21 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
mas01cr@239 22 lock.l_whence = SEEK_SET;
mas01cr@239 23 lock.l_start = 0;
mas01cr@239 24 lock.l_len = 0; /* "the whole file" */
mas01cr@239 25
mas01cr@239 26 retry:
mas01cr@239 27 do {
mas01cr@239 28 status = fcntl(fd, F_SETLKW, &lock);
mas01cr@239 29 } while (status != 0 && errno == EINTR);
mas01cr@239 30
mas01cr@239 31 if (status) {
mas01cr@239 32 if (errno == EAGAIN) {
mas01cr@239 33 sleep(1);
mas01cr@239 34 goto retry;
mas01cr@239 35 } else {
mas01cr@385 36 return status;
mas01cr@239 37 }
mas01cr@239 38 }
mas01cr@385 39 return 0;
mas01cr@239 40 }
mas01cr@239 41
mas01cr@385 42 int divest_lock(int fd) {
mas01cr@239 43 struct flock lock;
mas01cr@239 44
mas01cr@239 45 lock.l_type = F_UNLCK;
mas01cr@239 46 lock.l_whence = SEEK_SET;
mas01cr@239 47 lock.l_start = 0;
mas01cr@239 48 lock.l_len = 0;
mas01cr@239 49
mas01cr@385 50 return fcntl(fd, F_SETLKW, &lock);
mas01cr@385 51 }
mas01cr@239 52
mas01cr@385 53 void audioDB::get_lock(int fd, bool exclusive) {
mas01cr@385 54 if(acquire_lock(fd, exclusive)) {
mas01cr@385 55 error("fcntl lock error", "", "fcntl");
mas01cr@385 56 }
mas01cr@385 57 }
mas01cr@385 58
mas01cr@385 59 void audioDB::release_lock(int fd) {
mas01cr@385 60 if (divest_lock(fd)) {
mas01cr@239 61 error("fcntl unlock error", "", "fcntl");
mas01cr@385 62 }
mas01cr@239 63 }
mas01cr@239 64
mas01cr@239 65 void audioDB::error(const char* a, const char* b, const char *sysFunc) {
mas01ik@355 66
mas01ik@355 67
mas01ik@355 68 if(isServer) {
mas01cr@370 69 /* FIXME: I think this is leaky -- we never delete err.
mas01cr@370 70 actually deleting it is tricky, though; it gets placed into
mas01cr@370 71 some soap-internal struct with uncertain extent... -- CSR,
mas01cr@370 72 2007-10-01 */
mas01cr@370 73 char *err = new char[256]; /* FIXME: overflows */
mas01cr@370 74 snprintf(err, 255, "%s: %s\n%s", a, b, sysFunc ? strerror(errno) : "");
mas01cr@370 75 /* FIXME: actually we could usefully do with a properly
mas01cr@370 76 structured type, so that we can throw separate faultstring
mas01cr@370 77 and details. -- CSR, 2007-10-01 */
mas01ik@355 78 throw(err);
mas01ik@355 79 } else if (UseApiError){
mas01ik@355 80 apierrortemp=-1;
mas01ik@355 81 throw(apierrortemp);
mas01ik@355 82 } else {
mas01ik@355 83 std::cerr << a << ": " << b << std::endl;
mas01ik@355 84 if (sysFunc) {
mas01ik@355 85 perror(sysFunc);
mas01ik@355 86 }
mas01ik@355 87 exit(1);
mas01cr@239 88 }
mas01ik@355 89
mas01cr@239 90 }
mas01cr@239 91
mas01cr@284 92 void audioDB::initRNG() {
mas01cr@284 93 rng = gsl_rng_alloc(gsl_rng_mt19937);
mas01cr@284 94 if(!rng) {
mas01cr@284 95 error("could not allocate Random Number Generator");
mas01cr@284 96 }
mas01cr@284 97 /* FIXME: maybe we should use a real source of entropy? */
mas01cr@284 98 gsl_rng_set(rng, time(NULL));
mas01cr@284 99 }
mas01cr@284 100
mas01cr@239 101 void audioDB::initDBHeader(const char* dbName) {
mas01cr@392 102 if(!adb) {
mas01cr@395 103 adb = audiodb_open(dbName, forWrite ? O_RDWR : O_RDONLY);
mas01cr@395 104 if(!adb) {
mas01cr@395 105 error("Failed to open database", dbName);
mas01cr@395 106 }
mas01cr@239 107 }
mas01cr@392 108 dbfid = adb->fd;
mas01cr@392 109 dbH = adb->header;
mas01cr@239 110
mas01cr@239 111 CHECKED_MMAP(char *, db, 0, getpagesize());
mas01cr@239 112
mas01cr@239 113 // Make some handy tables with correct types
mas01cr@239 114 if(forWrite || (dbH->length > 0)) {
mas01cr@239 115 if(forWrite) {
mas01cr@239 116 fileTableLength = dbH->trackTableOffset - dbH->fileTableOffset;
mas01cr@239 117 trackTableLength = dbH->dataOffset - dbH->trackTableOffset;
mas01cr@239 118 dataBufLength = dbH->timesTableOffset - dbH->dataOffset;
mas01cr@239 119 timesTableLength = dbH->powerTableOffset - dbH->timesTableOffset;
mas01cr@239 120 powerTableLength = dbH->l2normTableOffset - dbH->powerTableOffset;
mas01cr@239 121 l2normTableLength = dbH->dbSize - dbH->l2normTableOffset;
mas01cr@239 122 } else {
mas01cr@256 123 fileTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01cr@256 124 trackTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_TRACKTABLE_ENTRY_SIZE);
mas01mc@324 125 if( dbH->flags & O2_FLAG_LARGE_ADB ){
mas01mc@324 126 dataBufLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01mc@324 127 timesTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01mc@324 128 powerTableLength = ALIGN_PAGE_UP(dbH->numFiles * O2_FILETABLE_ENTRY_SIZE);
mas01mc@324 129 l2normTableLength = 0;
mas01mc@324 130 }
mas01mc@324 131 else{
mas01mc@324 132 dataBufLength = ALIGN_PAGE_UP(dbH->length);
mas01mc@324 133 timesTableLength = ALIGN_PAGE_UP(2*(dbH->length / dbH->dim));
mas01mc@324 134 powerTableLength = ALIGN_PAGE_UP(dbH->length / dbH->dim);
mas01mc@324 135 l2normTableLength = ALIGN_PAGE_UP(dbH->length / dbH->dim);
mas01mc@324 136 }
mas01cr@239 137 }
mas01cr@239 138 CHECKED_MMAP(char *, fileTable, dbH->fileTableOffset, fileTableLength);
mas01cr@239 139 CHECKED_MMAP(unsigned *, trackTable, dbH->trackTableOffset, trackTableLength);
mas01cr@239 140 /*
mas01cr@239 141 * No more mmap() for dataBuf
mas01cr@239 142 *
mas01cr@239 143 * FIXME: Actually we do do the mmap() in the two cases where it's
mas01cr@239 144 * still "needed": in pointQuery and in l2norm if dbH->length is
mas01cr@239 145 * non-zero. Removing those cases too (and deleting the dataBuf
mas01cr@239 146 * variable completely) would be cool. -- CSR, 2007-11-19
mas01cr@239 147 *
mas01cr@239 148 * CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dataBufLength);
mas01cr@239 149 */
mas01mc@324 150 if( dbH->flags & O2_FLAG_LARGE_ADB ){
mas01mc@324 151 CHECKED_MMAP(char *, featureFileNameTable, dbH->dataOffset, fileTableLength);
mas01mc@324 152 if( dbH->flags & O2_FLAG_TIMES )
mas01mc@324 153 CHECKED_MMAP(char *, timesFileNameTable, dbH->timesTableOffset, fileTableLength);
mas01mc@324 154 if( dbH->flags & O2_FLAG_POWER )
mas01mc@324 155 CHECKED_MMAP(char *, powerFileNameTable, dbH->powerTableOffset, fileTableLength);
mas01mc@324 156 }
mas01mc@324 157 else{
mas01mc@324 158 CHECKED_MMAP(double *, timesTable, dbH->timesTableOffset, timesTableLength);
mas01mc@324 159 CHECKED_MMAP(double *, powerTable, dbH->powerTableOffset, powerTableLength);
mas01mc@324 160 CHECKED_MMAP(double *, l2normTable, dbH->l2normTableOffset, l2normTableLength);
mas01mc@324 161 }
mas01cr@239 162 }
mas01mc@292 163
mas01mc@292 164 // build track offset table
mas01mc@292 165 trackOffsetTable = new off_t[dbH->numFiles];
mas01mc@292 166 Uns32T cumTrack=0;
mas01mc@292 167 for(Uns32T k = 0; k < dbH->numFiles; k++){
mas01mc@292 168 trackOffsetTable[k] = cumTrack;
mas01mc@292 169 cumTrack += trackTable[k] * dbH->dim;
mas01mc@324 170 }
mas01mc@324 171
mas01mc@324 172 // Assign correct number of point bits per track in LSH indexing / retrieval
mas01mc@324 173 lsh_n_point_bits = dbH->flags >> 28;
mas01mc@324 174 if( !lsh_n_point_bits )
mas01mc@324 175 lsh_n_point_bits = O2_DEFAULT_LSH_N_POINT_BITS;
mas01cr@239 176 }
mas01cr@239 177
mas01mc@324 178 void audioDB::initInputFile (const char *inFile, bool loadData) {
mas01cr@239 179 if (inFile) {
mas01cr@239 180 if ((infid = open(inFile, O_RDONLY)) < 0) {
mas01cr@239 181 error("can't open input file for reading", inFile, "open");
mas01cr@239 182 }
mas01cr@239 183
mas01cr@239 184 if (fstat(infid, &statbuf) < 0) {
mas01cr@239 185 error("fstat error finding size of input", inFile, "fstat");
mas01cr@239 186 }
mas01cr@239 187
mas01cr@239 188 if(dbH->dim == 0 && dbH->length == 0) { // empty database
mas01cr@239 189 // initialize with input dimensionality
mas01cr@239 190 if(read(infid, &dbH->dim, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@239 191 error("short read of input file", inFile);
mas01cr@239 192 }
mas01cr@239 193 if(dbH->dim == 0) {
mas01cr@239 194 error("dimensionality of zero in input file", inFile);
mas01cr@239 195 }
mas01cr@239 196 } else {
mas01cr@239 197 unsigned test;
mas01cr@239 198 if(read(infid, &test, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@239 199 error("short read of input file", inFile);
mas01cr@239 200 }
mas01cr@239 201 if(dbH->dim == 0) {
mas01cr@239 202 error("dimensionality of zero in input file", inFile);
mas01cr@239 203 }
mas01cr@239 204 if(dbH->dim != test) {
mas01cr@239 205 std::cerr << "error: expected dimension: " << dbH->dim << ", got : " << test <<std::endl;
mas01cr@239 206 error("feature dimensions do not match database table dimensions", inFile);
mas01cr@239 207 }
mas01cr@239 208 }
mas01cr@239 209
mas01mc@324 210 if (loadData && ((indata = (char *) mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, infid, 0)) == (caddr_t) -1)) {
mas01cr@239 211 error("mmap error for input", inFile, "mmap");
mas01cr@239 212 }
mas01cr@239 213 }
mas01cr@239 214 }
mas01cr@239 215
mas01mc@292 216 void audioDB::initTables(const char* dbName, const char* inFile) {
mas01cr@284 217 /* FIXME: initRNG() really logically belongs in the audioDB
mas01cr@284 218 contructor. However, there are of the order of four constructors
mas01cr@284 219 at the moment, and more to come from API implementation. Given
mas01cr@284 220 that duplication, I think this is the least worst place to put
mas01cr@284 221 it; the assumption is that nothing which doesn't look at a
mas01cr@284 222 database will need an RNG. -- CSR, 2008-07-02 */
mas01cr@284 223 initRNG();
mas01cr@239 224 initDBHeader(dbName);
mas01mc@292 225 if(inFile)
mas01mc@292 226 initInputFile(inFile);
mas01cr@239 227 }
mas01mc@292 228
mas01mc@324 229 // If name is relative path, side effect name with prefix/name
mas01mc@324 230 // Do not free original pointer
mas01mc@324 231 void audioDB::prefix_name(char** const name, const char* prefix){
mas01mc@324 232 // No prefix if prefix is empty
mas01mc@324 233 if(!prefix)
mas01mc@324 234 return;
mas01mc@324 235 // Allocate new memory, keep old memory
mas01mc@324 236 assert(name && *name);
mas01mc@324 237 if (strlen(*name) + strlen(prefix) + 1 > O2_MAXFILESTR)
mas01mc@324 238 error("error: path prefix + filename too long",prefix);
mas01mc@324 239 // Do not prefix absolute path+filename
mas01mc@324 240 if(**name=='/')
mas01mc@324 241 return;
mas01mc@324 242 // OK to prefix relative path+filename
mas01mc@324 243 char* prefixedName = (char*) malloc(O2_MAXFILESTR);
mas01mc@324 244 sprintf(prefixedName, "%s/%s", prefix, *name);
mas01mc@324 245 *name = prefixedName; // side effect new name to old name
mas01mc@324 246 }