{"record":{"id":"7cb454c8185603c0","repo":"didi/DoKit","slug":"negative-size-bitmap","errorCode":null,"errorMessage":"Negative size: \" + bitmap","messagePattern":"Negative size: \" \\+ bitmap","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/Utils.java","lineNumber":116,"sourceCode":"    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n  */\n  private static final int WEBP_FILE_HEADER_SIZE = 12;\n  private static final String WEBP_FILE_HEADER_RIFF = \"RIFF\";\n  private static final String WEBP_FILE_HEADER_WEBP = \"WEBP\";\n\n  private Utils() {\n    // No instances.\n  }\n\n  static int getBitmapBytes(Bitmap bitmap) {\n    int result;\n    if (SDK_INT >= HONEYCOMB_MR1) {\n      result = BitmapHoneycombMR1.getByteCount(bitmap);\n    } else {\n      result = bitmap.getRowBytes() * bitmap.getHeight();\n    }\n    if (result < 0) {\n      throw new IllegalStateException(\"Negative size: \" + bitmap);\n    }\n    return result;\n  }\n\n  static <T> T checkNotNull(T value, String message) {\n    if (value == null) {\n      throw new NullPointerException(message);\n    }\n    return value;\n  }\n\n  static void checkNotMain() {\n    if (isMain()) {\n      throw new IllegalStateException(\"Method call should not happen from the main thread.\");\n    }\n  }\n\n  static void checkMain() {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/Utils.java#L98-L134","documentation":"Utils.getBitmapBytes(Bitmap) computes a bitmap's byte size — getByteCount() on API 12+, otherwise rowBytes * height — and throws IllegalStateException if the result is negative. A negative value means the arithmetic overflowed int (rowBytes * height exceeded 2^31) or the bitmap is in an invalid state; the library treats it as an unrecoverable accounting error because cache sizing and stats depend on it.","triggerScenarios":"On pre-Honeycomb MR1 devices, loading or creating a bitmap whose rowBytes * height overflows Integer.MAX_VALUE (over ~2GB, e.g. decoding a huge photo without downsampling); extremely rarely, a bitmap whose dimensions report nonsense values.","commonSituations":"Decoding a very large camera image at full resolution into memory with no inSampleSize; old-device (API < 12) code paths in legacy builds; OOM-adjacent situations where a bitmap larger than 2GB is attempted.","solutions":["Downsample large sources: use .resize(targetW, targetH).onlyScaleDown() on the request, or BitmapFactory.Options.inSampleSize for manual decoding.","Target view-sized dimensions rather than native image dimensions for all loads.","If it reproduces only on ancient devices, gate huge-image features by device memory class (ActivityManager.getMemoryClass())."],"exampleFix":"// before\npicasso.load(hugePhotoUrl).into(imageView); // full-res decode, overflows byte count\n\n// after\npicasso.load(hugePhotoUrl)\n    .resize(imageView.getMaxWidth(), imageView.getMaxHeight())\n    .onlyScaleDown()\n    .centerInside()\n    .into(imageView);","handlingStrategy":"validation","validationCode":"// Bound the decode size before loading\nint maxDim = context.getResources().getDisplayMetrics().widthPixels;\npicasso.load(url).resize(maxDim, maxDim).onlyScaleDown().centerInside().into(iv);","typeGuard":null,"tryCatchPattern":"Not applicable — the throw indicates corrupted size accounting; prevent by bounding bitmap dimensions.","preventionTips":["Never decode huge sources at native resolution; always resize/onlyScaleDown.","Watch memory class on old devices; cap image sizes accordingly.","Treat any occurrence as an out-of-memory-adjacent bug and fix sizing."],"tags":["android","picasso","bitmap","memory","overflow"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}