309f4ff097395a9427eca2bb956fc052bd1d596a kent Tue Feb 26 17:24:59 2013 -0800 Fixing a bug that caused crashes and error messages on beds with lots of blocks. diff --git src/lib/basicBed.c src/lib/basicBed.c index 9da7425..f6137ed 100644 --- src/lib/basicBed.c +++ src/lib/basicBed.c @@ -1336,37 +1336,33 @@ char *asStandardText = bedAsDef(15,15); asStandard = asParseText(asStandardText); result = asCompareObjs("Yours", asYours, "BED Standard", asStandard, numColumnsToCheck, NULL, abortOnDifference); freeMem(asStandardText); asObjectFreeList(&asStandard); return result; } void loadAndValidateBed(char *row[], int wordCount, int fieldCount, struct lineFile *lf, struct bed * bed, struct asObject *as, boolean isCt) /* Convert a row of strings to a bed and validate the contents. Abort with message if invalid data. Optionally validate bedPlus via asObject. * If a customTrack, then some errors are tolerated. */ { int count; int *blockSizes = NULL; -int tempBlockSizes[1024]; int *chromStarts; -int tempChromStarts[1024]; int *expIds; -int tempExpIds[1024]; float *expScores; -float tempExpScores[1024]; bed->chrom = row[0]; // note this value is not cloned for speed, callers may need to clone it. // This check is usually redundant since the caller should be checking it against actual chromInfo names // however hgLoadBed might not always have that info available. if (strlen(bed->chrom) >= BB_MAX_CHROM_STRING) // must leave room for 0 terminator lineFileAbort(lf, "chrom [%s] is too long (must not exceed %d characters)", bed->chrom, BB_MAX_CHROM_STRING - 1); if (strlen(bed->chrom) < 1) lineFileAbort(lf, "chrom cannot be blank or empty"); lineFileAllInts(lf, row, 1, &bed->chromStart, FALSE, 4, "integer", FALSE); lineFileAllInts(lf, row, 2, &bed->chromEnd, FALSE, 4, "integer", FALSE); if (bed->chromEnd < bed->chromStart) @@ -1430,71 +1426,76 @@ int numColors = lineFileAllIntsArray(lf, row, 8, colors, sizeof colors, FALSE, 1, "integer", FALSE); if (numColors == 3) { bed->itemRgb = (((unsigned)colors[0]) << 2*8) | (((unsigned)colors[1]) << 1*8) | (unsigned)colors[2]; } else lineFileAbort(lf, "Expecting color to consist of r,g,b values from 0 to 255. Got [%s]", saveColorString); freeMem(saveColorString); } else { lineFileAllInts(lf, row, 8, &bed->itemRgb, FALSE, 4, "integer", FALSE); } } +int tempArraySize = 1; // How big arrays are below if (wordCount > 9) { lineFileAllInts(lf, row, 9, &bed->blockCount, FALSE, 4, "integer", FALSE); if (!(bed->blockCount >= 1)) lineFileAbort(lf, "Expecting blockCount (%d) to be 1 or more.", bed->blockCount); - + tempArraySize = bed->blockCount; } +int tempBlockSizes[tempArraySize]; +int tempChromStarts[tempArraySize]; +int tempExpIds[tempArraySize]; +float tempExpScores[tempArraySize]; if (wordCount > 10) { if (isCt) { AllocArray(bed->blockSizes,bed->blockCount+1); // having +1 allows us to detect incorrect size count = lineFileAllIntsArray(lf, row, 10, bed->blockSizes, bed->blockCount+1, TRUE, 4, "integer", TRUE); blockSizes = bed->blockSizes; } else { - count = lineFileAllIntsArray(lf, row, 10, tempBlockSizes, sizeof tempBlockSizes, TRUE, 4, "integer", TRUE); + count = lineFileAllIntsArray(lf, row, 10, tempBlockSizes, tempArraySize, TRUE, 4, "integer", TRUE); blockSizes = tempBlockSizes; } if (count != bed->blockCount) lineFileAbort(lf, "Expecting %d elements in blockSizes list, found at least %d", bed->blockCount, count); int i; for (i=0; i < bed->blockCount; i++) { if (!(blockSizes[i] > 0)) lineFileAbort(lf, "BED blockSizes must be greater than 0, blockSize[%d] = %d", i, blockSizes[i]); } } if (wordCount > 11) { int i; if (isCt) { AllocArray(bed->chromStarts,bed->blockCount+1); // having +1 allows us to detect incorrect size count = lineFileAllIntsArray(lf, row, 11, bed->chromStarts, bed->blockCount+1, TRUE, 4, "integer", TRUE); chromStarts = bed->chromStarts; } else { - count = lineFileAllIntsArray(lf, row, 11, tempChromStarts, sizeof tempChromStarts, TRUE, 4, "integer", TRUE); + count = lineFileAllIntsArray(lf, row, 11, tempChromStarts, tempArraySize, TRUE, 4, "integer", TRUE); chromStarts = tempChromStarts; } if (count != bed->blockCount) lineFileAbort(lf, "Expecting %d elements in chromStarts list, found at least %d", bed->blockCount, count); // tell the user if they appear to be using absolute starts rather than // relative... easy to forget! Also check block order, coord ranges... if (chromStarts[0] != 0) lineFileAbort(lf, "BED blocks must span chromStart to chromEnd. " "BED chromStarts[0] = %d, must be 0 so that (chromStart + " "chromStarts[0]) equals chromStart.", chromStarts[0]); for (i=1; i < bed->blockCount; i++) { @@ -1527,45 +1528,45 @@ if (wordCount > 12) // get the microarray/colored-exon fields { lineFileAllInts(lf, row, 12, &bed->expCount, TRUE, 4, "integer", TRUE); if (!(bed->expCount >= 1)) lineFileAbort(lf, "Expecting expCount (%d) to be 1 or more.", bed->expCount); if (isCt) { AllocArray(bed->expIds,bed->expCount+1); // having +1 allows us to detect incorrect size count = lineFileAllIntsArray(lf, row, 13, bed->expIds, bed->expCount+1, TRUE, 4, "integer", TRUE); expIds = bed->expIds; } else { - count = lineFileAllIntsArray(lf, row, 13, tempExpIds, sizeof tempExpIds, TRUE, 4, "integer", TRUE); + count = lineFileAllIntsArray(lf, row, 13, tempExpIds, tempArraySize, TRUE, 4, "integer", TRUE); expIds = tempExpIds; } if (count != bed->expCount) lineFileAbort(lf, "expecting %d elements in expIds list (bed field 14)", bed->expCount); if (wordCount == 15) { if (isCt) { sqlFloatDynamicArray(row[14], &bed->expScores, &count); expScores = bed->expScores; } else { - count = sqlFloatArray(row[14], tempExpScores, sizeof tempExpScores); + count = sqlFloatArray(row[14], tempExpScores, tempArraySize); expScores = tempExpScores; } if (count != bed->expCount) lineFileAbort(lf, "expecting %d elements in expScores list (bed field 15)", bed->expCount); } } /* Check bedPlus fields are formatted right. */ /* This could form the basis of an .as-validator independent of BED. I suppose it could go in asParse.c */ if (as) { struct hash* linkHash = NULL; /* Validate as-fields */ struct asColumn *asCol = NULL; asCol = as->columnList;