5a884a9bce7e45d3f30423fd8e2e26bb7bc44b80 angie Wed Mar 23 10:50:57 2022 -0700 Fix memory error revealed by Lou & valgrind: use rowBuf in nextRowFromSqlResult so hashJoin doesn't write past end of mysql row storage. diff --git src/hg/cgilib/annoStreamDb.c src/hg/cgilib/annoStreamDb.c index a724497..fb5ff3e 100644 --- src/hg/cgilib/annoStreamDb.c +++ src/hg/cgilib/annoStreamDb.c @@ -161,33 +161,39 @@ annoStreamerSetRegion(vSelf, chrom, regionStart, regionEnd); struct annoStreamDb *self = (struct annoStreamDb *)vSelf; // If splitTable differs from table, use new chrom in splitTable: if (differentString(self->table, self->trackTable)) { char newSplitTable[PATH_LEN]; safef(newSplitTable, sizeof(newSplitTable), "%s_%s", chrom, self->trackTable); freeMem(self->table); self->table = cloneString(newSplitTable); } resetQueryState(self); asdUpdateBaselineQuery(self); } static char **nextRowFromSqlResult(struct annoStreamDb *self) -/* Stream rows directly from self->sr. */ +/* Stream rows directly from self->sr, but copy into rowBuf in case we need extra columns for + * hashJoin. */ { -return sqlNextRow(self->sr); +// Use only the first row in rowBuf. +if (self->rowBuf.buf[0] == NULL) + lmAllocArray(self->rowBuf.lm, self->rowBuf.buf[0], self->bigRowSize); +char **row = sqlNextRow(self->sr); +CopyArray(row, self->rowBuf.buf[0], self->sqlRowSize); +return self->rowBuf.buf[0]; } INLINE boolean useSplitTable(struct annoStreamDb *self, struct joinerDtf *dtf) /* Return TRUE if dtf matches self->{db,table} and table is split. */ { return (sameString(dtf->database, self->db) && sameString(dtf->table, self->trackTable) && differentString(self->table, self->trackTable)); } static void appendFieldList(struct annoStreamDb *self, struct dyString *query) /* Append SQL field list to query. */ { struct joinerDtf *fieldList = self->joinMixer ? self->joinMixer->sqlFieldList : self->mainTableDtfList; @@ -1311,30 +1317,31 @@ // Special case: genbank-updated tables are not sorted because new mappings are // tacked on at the end. Max didn't sort the pubs* tables but I hope he will // sort the tables for any future tracks. :) if (isIncrementallyUpdated(table) || isPubsTable(table)) self->notSorted = TRUE; self->mergeBins = FALSE; self->maxOutRows = maxOutRows; self->useMaxOutRows = (maxOutRows > 0); self->needQuery = TRUE; self->chromList = annoAssemblySeqNames(aa); if (slCount(self->chromList) > 1000) { // Assembly has many sequences (e.g. scaffold-based assembly) -- // don't break up into per-sequence queries. Take our chances // with mysql being unhappy about the sqlResult being open too long. + rowBufInit(&self->rowBuf, 1); self->doQuery = asdDoQuerySimple; self->nextRowRaw = nextRowFromSqlResult; } else { // All-chromosome assembly -- if table is large, perform a series of // chunked queries. self->doQuery = asdDoQueryChunking; self->nextRowRaw = nextRowFromBuffer; } asdInitBaselineQuery(self); asdUpdateBaselineQuery(self); struct annoStreamer *sSelf = (struct annoStreamer *)self; if (asdDebug) sSelf->getHeader = asdGetHeader;