public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: James Bottomley <jbottomley@odin.com>
To: "akpm@linux-foundation.org" <akpm@linux-foundation.org>
Cc: "linux@rasmusvillemoes.dk" <linux@rasmusvillemoes.dk>,
	"andriy.shevchenko@linux.intel.com" 
	<andriy.shevchenko@linux.intel.com>,
	"vkuznets@redhat.com" <vkuznets@redhat.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"kys@microsoft.com" <kys@microsoft.com>
Subject: Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
Date: Fri, 11 Sep 2015 18:31:07 +0000	[thread overview]
Message-ID: <1441996263.6276.4.camel@Odin.com> (raw)
In-Reply-To: <20150910160815.30d56ee48bbfdf5eed783c53@linux-foundation.org>

[-- Attachment #1: Type: text/plain, Size: 975 bytes --]

On Thu, 2015-09-10 at 16:08 -0700, Andrew Morton wrote:
> On Fri,  4 Sep 2015 14:56:33 +0200 Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> 
> > string_get_size(1, 512, 0, ..., ...) call results in an infinite loop. The
> > problem is that if size == 0 when we start calculating sf_cap this loop
> > will never end.
> > 
> > The caller causing the issue is sd_read_capacity(), the problem was noticed
> > on Hyper-V.
> 
> When fixing bugs, please provide enough info for others to be able to
> understand which kernel version(s) need the fix.  In this case: what
> end-user action triggers this bug?  (iow, how does sdkp->capacity
> become zero?)

Any more details.  The attached programme, which is cut straight out of
the algorithm in string_helpers.c and modified for a C environment
slightly (only in do_div and the typedefs) produces this

hello
STRING IS 512 B

With your input, so I don't think the problem is where you think it is.

James


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: test.c --]
[-- Type: text/x-csrc; name="test.c", Size: 2502 bytes --]

#include <sys/types.h>
#include <string.h>
#include <stdio.h>

# define do_div(n,base) ({					\
	u32 __base = (base);				\
	u32 __rem;						\
	__rem = ((u64)(n)) % __base;			\
	(n) = ((u64)(n)) / __base;				\
	__rem;							\
 })

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

typedef unsigned long long u64;
typedef unsigned int u32;

enum string_size_units {
  STRING_UNITS_2,
  STRING_UNITS_10,
};

/**
 * string_get_size - get the size in the specified units
 * @size:	The size to be converted in blocks
 * @blk_size:	Size of the block (use 1 for size in bytes)
 * @units:	units to use (powers of 1000 or 1024)
 * @buf:	buffer to format to
 * @len:	length of buffer
 *
 * This function returns a string formatted to 3 significant figures
 * giving the size in the required units.  @buf should have room for
 * at least 9 bytes and will always be zero terminated.
 *
 */
void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
		     char *buf, int len)
{
	static const char *const units_10[] = {
		"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
	};
	static const char *const units_2[] = {
		"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
	};
	static const char *const *const units_str[] = {
		[STRING_UNITS_10] = units_10,
		[STRING_UNITS_2] = units_2,
	};
	static const unsigned int divisor[] = {
		[STRING_UNITS_10] = 1000,
		[STRING_UNITS_2] = 1024,
	};
	int i, j;
	u32 remainder = 0, sf_cap, exp;
	char tmp[8];
	const char *unit;

	tmp[0] = '\0';
	i = 0;
	if (!size)
		goto out;

	while (blk_size >= divisor[units]) {
		remainder = do_div(blk_size, divisor[units]);
		i++;
	}

	exp = divisor[units] / (u32)blk_size;
	if (size >= exp) {
		remainder = do_div(size, divisor[units]);
		remainder *= blk_size;
		i++;
	} else {
		remainder *= size;
	}

	size *= blk_size;
	size += remainder / divisor[units];
	remainder %= divisor[units];

	while (size >= divisor[units]) {
		remainder = do_div(size, divisor[units]);
		i++;
	}

	sf_cap = size;
	for (j = 0; sf_cap*10 < 1000; j++)
		sf_cap *= 10;

	if (j) {
		remainder *= 1000;
		remainder /= divisor[units];
		snprintf(tmp, sizeof(tmp), ".%03u", remainder);
		tmp[j+1] = '\0';
	}

 out:
	if (i >= ARRAY_SIZE(units_2))
		unit = "UNK";
	else
		unit = units_str[units][i];

	snprintf(buf, len, "%u%s %s", (u32)size,
		 tmp, unit);
}

int main(char *argc[], int argv)
{
char buf[512];

printf("hello\n");
string_get_size(1, 512, STRING_UNITS_2, buf, sizeof(buf));
printf("STRING IS %s\n", buf);

}

  reply	other threads:[~2015-09-11 18:31 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-04 12:56 [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size() Vitaly Kuznetsov
2015-09-10 23:08 ` Andrew Morton
2015-09-11 18:31   ` James Bottomley [this message]
2015-09-14  9:06     ` Andy Shevchenko
2015-09-14 12:43       ` Vitaly Kuznetsov
2015-09-14 14:33         ` Andy Shevchenko
2015-09-14  9:16     ` Vitaly Kuznetsov
2015-09-11  1:22 ` James Bottomley
2015-09-14  9:19   ` Vitaly Kuznetsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1441996263.6276.4.camel@Odin.com \
    --to=jbottomley@odin.com \
    --cc=akpm@linux-foundation.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=kys@microsoft.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=vkuznets@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox