// Test that GDALTranslate() detects error in flush cache template<> template<> void object::test<8>() { GDALDriver* poDriver = new GDALDriver(); poDriver->SetDescription("DatasetWithErrorInFlushCache"); poDriver->pfnCreateCopy = DatasetWithErrorInFlushCache::CreateCopy; GetGDALDriverManager()->RegisterDriver( poDriver ); const char* args[] = { "-of", "DatasetWithErrorInFlushCache", NULL }; GDALTranslateOptions* psOptions = GDALTranslateOptionsNew((char**)args, NULL); GDALDatasetH hSrcDS = GDALOpen("../gcore/data/byte.tif", GA_ReadOnly); CPLErrorReset(); CPLPushErrorHandler(CPLQuietErrorHandler); GDALDatasetH hOutDS = GDALTranslate("", hSrcDS, psOptions, NULL); CPLPopErrorHandler(); GDALClose(hSrcDS); GDALTranslateOptionsFree(psOptions); ensure(hOutDS == NULL); ensure(CPLGetLastErrorType() != CE_None); GetGDALDriverManager()->DeregisterDriver( poDriver ); delete poDriver; }
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { VSILFILE* fp = VSIFileFromMemBuffer( "/vsimem/test.tar", reinterpret_cast<GByte*>(const_cast<uint8_t*>(buf)), len, FALSE ); VSIFCloseL(fp); CPLPushErrorHandler(CPLQuietErrorHandler); char** papszArgv = nullptr; // Prevent generating too big output raster. Make sure they are set at // the beginning to avoid being accidentally eaten by invalid arguments // afterwards. papszArgv = CSLAddString(papszArgv, "-limit_outsize"); papszArgv = CSLAddString(papszArgv, "1000000"); fp = VSIFOpenL("/vsitar//vsimem/test.tar/cmd.txt", "rb"); if( fp != nullptr ) { const char* pszLine = nullptr; while( (pszLine = CPLReadLineL(fp)) != nullptr ) { if( !EQUAL(pszLine, "-limit_outsize") ) papszArgv = CSLAddString(papszArgv, pszLine); } VSIFCloseL(fp); } int nXDim = -1; int nYDim = -1; bool bXDimPct = false; bool bYDimPct = false; bool bNonNearestResampling = false; int nBlockXSize = 0; int nBlockYSize = 0; bool bStatsEnabled = false; bool bHFA = false; if( papszArgv != nullptr ) { int nCount = CSLCount(papszArgv); for( int i = 0; i < nCount; i++ ) { if( EQUAL(papszArgv[i], "-outsize") && i + 2 < nCount ) { nXDim = atoi(papszArgv[i+1]); bXDimPct = (papszArgv[i+1][0] != '\0' && papszArgv[i+1][strlen(papszArgv[i+1])-1] == '%'); nYDim = atoi(papszArgv[i+2]); bYDimPct = (papszArgv[i+2][0] != '\0' && papszArgv[i+2][strlen(papszArgv[i+2])-1] == '%'); } else if( EQUAL(papszArgv[i], "-r") && i + 1 < nCount ) { bNonNearestResampling = !STARTS_WITH_CI(papszArgv[i+1], "NEAR"); } else if( EQUAL(papszArgv[i], "-co") && i + 1 < nCount ) { if( STARTS_WITH_CI(papszArgv[i+1], "BLOCKSIZE=") ) { nBlockXSize = std::max(nBlockXSize, atoi(papszArgv[i+1]+strlen("BLOCKSIZE="))); nBlockYSize = std::max(nBlockYSize, atoi(papszArgv[i+1]+strlen("BLOCKSIZE="))); } else if( STARTS_WITH_CI(papszArgv[i+1], "BLOCKXSIZE=") ) { nBlockXSize = std::max(nBlockXSize, atoi(papszArgv[i+1]+strlen("BLOCKXSIZE="))); } else if( STARTS_WITH_CI(papszArgv[i+1], "BLOCKYSIZE=") ) { nBlockYSize = std::max(nBlockYSize, atoi(papszArgv[i+1]+strlen("BLOCKYSIZE="))); } } else if( EQUAL(papszArgv[i], "-stats") ) { bStatsEnabled = true; } else if( EQUAL(papszArgv[i], "-of") && i + 1 < nCount ) { bHFA = EQUAL( papszArgv[i+1], "HFA" ); } } if( bHFA ) { // Disable statistics computation for HFA, as it can be time // consuming. // See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=10067 papszArgv = CSLInsertString(papszArgv, 0, "-co"); papszArgv = CSLInsertString(papszArgv, 1, "STATISTICS=NO"); } } if( papszArgv != nullptr ) { GDALTranslateOptions* psOptions = GDALTranslateOptionsNew(papszArgv, nullptr); if( psOptions ) { GDALDatasetH hSrcDS = GDALOpen( "/vsitar//vsimem/test.tar/in", GA_ReadOnly ); if( hSrcDS != nullptr ) { // Also check that reading the source doesn't involve too // much memory GDALDataset* poSrcDS = reinterpret_cast<GDALDataset*>(hSrcDS); int nBands = poSrcDS->GetRasterCount(); if( nBands < 10 ) { // Prevent excessive downsampling which might require huge // memory allocation bool bOKForResampling = true; if( bNonNearestResampling && nXDim >= 0 && nYDim >= 0 ) { if( bXDimPct && nXDim > 0 ) { nXDim = static_cast<int>( poSrcDS->GetRasterXSize() / 100.0 * nXDim); } if( bYDimPct && nYDim > 0 ) { nYDim = static_cast<int>( poSrcDS->GetRasterYSize() / 100.0 * nYDim); } if( nXDim > 0 && poSrcDS->GetRasterXSize() / nXDim > 100 ) bOKForResampling = false; if( nYDim > 0 && poSrcDS->GetRasterYSize() / nYDim > 100 ) bOKForResampling = false; } bool bOKForSrc = true; if( nBands ) { const int nDTSize = GDALGetDataTypeSizeBytes( poSrcDS->GetRasterBand(1)->GetRasterDataType() ); vsi_l_offset nSize = static_cast<vsi_l_offset>(nBands) * poSrcDS->GetRasterXSize() * poSrcDS->GetRasterYSize() * nDTSize; if( nSize > 10 * 1024 * 1024 ) { bOKForSrc = false; } int nBXSize = 0, nBYSize = 0; GDALGetBlockSize( GDALGetRasterBand(hSrcDS, 1), &nBXSize, &nBYSize ); const char* pszInterleave = GDALGetMetadataItem( hSrcDS, "INTERLEAVE", "IMAGE_STRUCTURE" ); int nSimultaneousBands = (pszInterleave && EQUAL(pszInterleave, "PIXEL")) ? nBands : 1; if( static_cast<GIntBig>(nSimultaneousBands)* nBXSize * nBYSize * nDTSize > 10 * 1024 * 1024 ) { bOKForSrc = false; } if( static_cast<GIntBig>(nBlockXSize) * nBlockYSize > 10 * 1024 * 1024 / (nBands * nDTSize) ) { bOKForSrc = false; } } bool bOKForStats = true; if( nBands && bStatsEnabled ) { // Other types might be too slow with sanitization enabled // See https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=10029 bOKForStats = poSrcDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte; } if( bOKForSrc && bOKForResampling && bOKForStats ) { GDALDatasetH hOutDS = GDALTranslate("/vsimem/out", hSrcDS, psOptions, nullptr); if( hOutDS ) GDALClose(hOutDS); } } GDALClose(hSrcDS); } GDALTranslateOptionsFree(psOptions); } } CSLDestroy(papszArgv); VSIRmdirRecursive("/vsimem/"); CPLPopErrorHandler(); return 0; }
MAIN_START(argc, argv) { /* Check strict compilation and runtime library version as we use C++ API */ if (! GDAL_CHECK_VERSION(argv[0])) exit(1); EarlySetConfigOptions(argc, argv); /* -------------------------------------------------------------------- */ /* Register standard GDAL drivers, and process generic GDAL */ /* command options. */ /* -------------------------------------------------------------------- */ GDALAllRegister(); argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); if( argc < 1 ) exit( -argc ); for( int i = 0; argv != nullptr && argv[i] != nullptr; i++ ) { if( EQUAL(argv[i], "--utility_version") ) { printf("%s was compiled against GDAL %s and is running against GDAL %s\n", argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME")); CSLDestroy( argv ); return 0; } else if( EQUAL(argv[i],"--help") ) { Usage(nullptr); } else if ( EQUAL(argv[i], "--long-usage") ) { Usage(nullptr, FALSE); } } /* -------------------------------------------------------------------- */ /* Set optimal setting for best performance with huge input VRT. */ /* The rationale for 450 is that typical Linux process allow */ /* only 1024 file descriptors per process and we need to keep some */ /* spare for shared libraries, etc. so let's go down to 900. */ /* And some datasets may need 2 file descriptors, so divide by 2 */ /* for security. */ /* -------------------------------------------------------------------- */ if( CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", nullptr) == nullptr ) { #if defined(__MACH__) && defined(__APPLE__) // On Mach, the default limit is 256 files per process // TODO We should eventually dynamically query the limit for all OS CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "100"); #else CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450"); #endif } GDALTranslateOptionsForBinary* psOptionsForBinary = GDALTranslateOptionsForBinaryNew(); GDALTranslateOptions *psOptions = GDALTranslateOptionsNew(argv + 1, psOptionsForBinary); CSLDestroy( argv ); if( psOptions == nullptr ) { Usage(nullptr); } if( psOptionsForBinary->pszSource == nullptr ) { Usage("No source dataset specified."); } if( psOptionsForBinary->pszDest == nullptr ) { Usage("No target dataset specified."); } if( strcmp(psOptionsForBinary->pszDest, "/vsistdout/") == 0 ) { psOptionsForBinary->bQuiet = TRUE; } if( !(psOptionsForBinary->bQuiet) ) { GDALTranslateOptionsSetProgress(psOptions, GDALTermProgress, nullptr); } if( psOptionsForBinary->pszFormat ) { GDALDriverH hDriver = GDALGetDriverByName( psOptionsForBinary->pszFormat ); if( hDriver == nullptr ) { fprintf(stderr, "Output driver `%s' not recognised.\n", psOptionsForBinary->pszFormat); fprintf(stderr, "The following format drivers are configured and support output:\n" ); for( int iDr = 0; iDr < GDALGetDriverCount(); iDr++ ) { hDriver = GDALGetDriver(iDr); if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, nullptr) != nullptr && (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, nullptr ) != nullptr || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, nullptr ) != nullptr) ) { fprintf(stderr, " %s: %s\n", GDALGetDriverShortName( hDriver ), GDALGetDriverLongName( hDriver ) ); } } GDALTranslateOptionsFree(psOptions); GDALTranslateOptionsForBinaryFree(psOptionsForBinary); GDALDestroyDriverManager(); exit(1); } } /* -------------------------------------------------------------------- */ /* Attempt to open source file. */ /* -------------------------------------------------------------------- */ GDALDatasetH hDataset = GDALOpenEx(psOptionsForBinary->pszSource, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, nullptr, psOptionsForBinary->papszOpenOptions, nullptr); if( hDataset == nullptr ) { GDALDestroyDriverManager(); exit( 1 ); } /* -------------------------------------------------------------------- */ /* Handle subdatasets. */ /* -------------------------------------------------------------------- */ if( !psOptionsForBinary->bCopySubDatasets && GDALGetRasterCount(hDataset) == 0 && CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0 ) { fprintf( stderr, "Input file contains subdatasets. Please, select one of them for reading.\n" ); GDALClose( hDataset ); GDALDestroyDriverManager(); exit( 1 ); } int bUsageError = FALSE; GDALDatasetH hOutDS = nullptr; if( psOptionsForBinary->bCopySubDatasets && CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0 ) { char **papszSubdatasets = GDALGetMetadata(hDataset,"SUBDATASETS"); char *pszSubDest = static_cast<char *>( CPLMalloc(strlen(psOptionsForBinary->pszDest) + 32)); CPLString osPath = CPLGetPath(psOptionsForBinary->pszDest); CPLString osBasename = CPLGetBasename(psOptionsForBinary->pszDest); CPLString osExtension = CPLGetExtension(psOptionsForBinary->pszDest); CPLString osTemp; const char* pszFormat = nullptr; if ( CSLCount(papszSubdatasets)/2 < 10 ) { pszFormat = "%s_%d"; } else if ( CSLCount(papszSubdatasets)/2 < 100 ) { pszFormat = "%s_%002d"; } else { pszFormat = "%s_%003d"; } const char* pszDest = pszSubDest; for( int i = 0; papszSubdatasets[i] != nullptr; i += 2 ) { char* pszSource = CPLStrdup(strstr(papszSubdatasets[i],"=")+1); osTemp = CPLSPrintf( pszFormat, osBasename.c_str(), i/2 + 1 ); osTemp = CPLFormFilename( osPath, osTemp, osExtension ); strcpy( pszSubDest, osTemp.c_str() ); hDataset = GDALOpenEx( pszSource, GDAL_OF_RASTER, nullptr, psOptionsForBinary->papszOpenOptions, nullptr ); CPLFree(pszSource); if( !psOptionsForBinary->bQuiet ) printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset)); hOutDS = GDALTranslate(pszDest, hDataset, psOptions, &bUsageError); if(bUsageError == TRUE) Usage(); if (hOutDS == nullptr) break; GDALClose(hOutDS); } GDALClose(hDataset); GDALTranslateOptionsFree(psOptions); GDALTranslateOptionsForBinaryFree(psOptionsForBinary); CPLFree(pszSubDest); GDALDestroyDriverManager(); return 0; } if( !psOptionsForBinary->bQuiet ) printf("Input file size is %d, %d\n", GDALGetRasterXSize(hDataset), GDALGetRasterYSize(hDataset)); hOutDS = GDALTranslate(psOptionsForBinary->pszDest, hDataset, psOptions, &bUsageError); if(bUsageError == TRUE) Usage(); int nRetCode = hOutDS ? 0 : 1; /* Close hOutDS before hDataset for the -f VRT case */ GDALClose(hOutDS); GDALClose(hDataset); GDALTranslateOptionsFree(psOptions); GDALTranslateOptionsForBinaryFree(psOptionsForBinary); GDALDestroyDriverManager(); return nRetCode; }