diff mbox

[2/2] pre-process: replace use of vla's with heap allocation

Message ID CANeU7QkmtVVPhhanR2M7=3P9cCse0B9rXJSfx8c1NCC4aHZ-qw@mail.gmail.com (mailing list archive)
State Rejected, archived
Headers show

Commit Message

Christopher Li July 20, 2017, 12:02 p.m. UTC
On Wed, Jul 19, 2017 at 4:13 PM, Ramsay Jones
<ramsay@ramsayjones.plus.com> wrote:
>
> The 'selfcheck' make target issues warnings about using vla's in the
> pre-processor code, like so:
>
>        CHECK    pre-process.c
>   pre-process.c:712:25: warning: Variable length array is used.
>   pre-process.c:2019:28: warning: Variable length array is used.
>
> A Makefile change to pass '-Wno-vla' to sparse when processing this
> source file (or all source files) may be a better solution than the
> one given here.
>
> Replace the use of vla's with heap allocation. This has performance
> implications (although it may me safer), due to the dynamic memory
> allocation and the zero initialisation of the memory (using calloc).
> I have not done any timing measurements to see if this is a problem
> in practice.

I purpose the following patch. Make the expand using stack for small
argument numbers. That should not have much performance impact
at all because long macro arguments are rare.

Incremental patch follows. If you think that is fine, I will apply the
combined patch as yours.

> +       if (nargs > 0)
> +               args = calloc(nargs, sizeof(*args));

Need to check alloc failed.

> +
>         if (sym->arglist) {
>                 if (!match_op(scan_next(&token->next), '('))
>                         return 1;

Need to free alloc memory.


> +       if (nargs > 0)
> +               args = calloc(nargs, sizeof(*args));

Same here need to check alloc failed.

Chris

Purposed incremental fix up follows:

endop, struct token *start)
@@ -2024,8 +2035,11 @@ static void dump_macro(struct symbol *sy
  struct token **args = NULL;
  struct token *token;

- if (nargs > 0)
+ if (nargs > 0) {
  args = calloc(nargs, sizeof(*args));
+ if (!args)
+ die("calloc %ld", nargs * sizeof(*args));
+ }

  printf("#define %s", show_ident(sym->ident));
  token = sym->arglist;
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Ramsay Jones July 20, 2017, 4:44 p.m. UTC | #1
On 20/07/17 13:02, Christopher Li wrote:
> On Wed, Jul 19, 2017 at 4:13 PM, Ramsay Jones
> <ramsay@ramsayjones.plus.com> wrote:
>>
>> The 'selfcheck' make target issues warnings about using vla's in the
>> pre-processor code, like so:
>>
>>        CHECK    pre-process.c
>>   pre-process.c:712:25: warning: Variable length array is used.
>>   pre-process.c:2019:28: warning: Variable length array is used.
>>
>> A Makefile change to pass '-Wno-vla' to sparse when processing this
>> source file (or all source files) may be a better solution than the
>> one given here.
>>
>> Replace the use of vla's with heap allocation. This has performance
>> implications (although it may me safer), due to the dynamic memory
>> allocation and the zero initialisation of the memory (using calloc).
>> I have not done any timing measurements to see if this is a problem
>> in practice.
> 
> I purpose the following patch. Make the expand using stack for small
> argument numbers. That should not have much performance impact
> at all because long macro arguments are rare.

My first reaction was surprise that you didn't go for the Makefile
idea - setting '-Wno-vla' would be the simplest solution. ;-)

I can understand warning about vla usage (especially in the kernel),
but it a 'standard' supported feature. I don't use them myself, partly
because they are a 'relatively' new feature, but also because I have had
some bad experience in the past using alloca in similar circumstances.

My second thought was, have you done some timing tests (no I haven't)
and determined that this causes a noticeable slowdown?

> Incremental patch follows. If you think that is fine, I will apply the
> combined patch as yours.
> 
>> +       if (nargs > 0)
>> +               args = calloc(nargs, sizeof(*args));
> 
> Need to check alloc failed.

Yes, indeed! *blush*

>> +
>>         if (sym->arglist) {
>>                 if (!match_op(scan_next(&token->next), '('))
>>                         return 1;
> 
> Need to free alloc memory.

Ahem, I obviously didn't think about this patch too much! :-D

> 
> 
>> +       if (nargs > 0)
>> +               args = calloc(nargs, sizeof(*args));
> 
> Same here need to check alloc failed.
> 
> Chris
> 
> Purposed incremental fix up follows:

Hmm, dunno.

I did, briefly, think about adding an 'array' capability to the
sparse ALLOCATOR facility (you can only allocate single instances
from the current allocators - ignoring 'string' and 'bytes').

ATB,
Ramsay Jones

> 
> --- sparse.chrisl.orig/pre-process.c
> +++ sparse.chrisl/pre-process.c
> @@ -709,21 +709,30 @@ static int expand(struct token **list, s
>   struct ident *expanding = token->ident;
>   struct token **tail;
>   int nargs = sym->arglist ? sym->arglist->count.normal : 0;
> - struct arg *args = NULL;
> +#define ARG_LIMIT 8
> + struct arg arg_array[ARG_LIMIT], *args = arg_array;
> + int err = 0;
> 
>   if (expanding->tainted) {
>   token->pos.noexpand = 1;
>   return 1;
>   }
> 
> - if (nargs > 0)
> + if (nargs >= ARG_LIMIT) {
>   args = calloc(nargs, sizeof(*args));
> + if (!args)
> + die("calloc(%d, %lu) failed", nargs, sizeof(*args));
> + }
> 
>   if (sym->arglist) {
> - if (!match_op(scan_next(&token->next), '('))
> - return 1;
> - if (!collect_arguments(token->next, sym->arglist, args, token))
> - return 1;
> + if (!match_op(scan_next(&token->next), '(')) {
> + err = 1;
> + goto exit;
> + }
> + if (!collect_arguments(token->next, sym->arglist, args, token)) {
> + err = 1;
> + goto exit;
> + }
>   expand_arguments(nargs, args);
>   }
> 
> @@ -741,9 +750,11 @@ static int expand(struct token **list, s
>   (*list)->pos.whitespace = token->pos.whitespace;
>   *tail = last;
> 
> - free(args);
> +exit:
> + if (nargs >= ARG_LIMIT)
> + free(args);
> 
> - return 0;
> + return err;
>  }
> 
>  static const char *token_name_sequence(struct token *token, int
> endop, struct token *start)
> @@ -2024,8 +2035,11 @@ static void dump_macro(struct symbol *sy
>   struct token **args = NULL;
>   struct token *token;
> 
> - if (nargs > 0)
> + if (nargs > 0) {
>   args = calloc(nargs, sizeof(*args));
> + if (!args)
> + die("calloc %ld", nargs * sizeof(*args));
> + }
> 
>   printf("#define %s", show_ident(sym->ident));
>   token = sym->arglist;
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck July 29, 2017, 1:17 p.m. UTC | #2
On Thu, Jul 20, 2017 at 6:44 PM, Ramsay Jones
<ramsay@ramsayjones.plus.com> wrote:
>
>
> On 20/07/17 13:02, Christopher Li wrote:
>> On Wed, Jul 19, 2017 at 4:13 PM, Ramsay Jones
>> <ramsay@ramsayjones.plus.com> wrote:
>>>
>>> The 'selfcheck' make target issues warnings about using vla's in the
>>> pre-processor code, like so:
>>>
>>>        CHECK    pre-process.c
>>>   pre-process.c:712:25: warning: Variable length array is used.
>>>   pre-process.c:2019:28: warning: Variable length array is used.
>>>
>>> A Makefile change to pass '-Wno-vla' to sparse when processing this
>>> source file (or all source files) may be a better solution than the
>>> one given here.
>>>
>>> Replace the use of vla's with heap allocation. This has performance
>>> implications (although it may me safer), due to the dynamic memory
>>> allocation and the zero initialisation of the memory (using calloc).
>>> I have not done any timing measurements to see if this is a problem
>>> in practice.
>>
>> I purpose the following patch. Make the expand using stack for small
>> argument numbers. That should not have much performance impact
>> at all because long macro arguments are rare.
>
> My first reaction was surprise that you didn't go for the Makefile
> idea - setting '-Wno-vla' would be the simplest solution. ;-)
>
> I can understand warning about vla usage (especially in the kernel),
> but it a 'standard' supported feature. I don't use them myself, partly
> because they are a 'relatively' new feature, but also because I have had
> some bad experience in the past using alloca in similar circumstances.

I second this opinion.
In the kernel, stacks are quite small and it's very natural to:
- limit stack use to the minimal
- control stack usage
and so VLAs are avoided (but not banned).
But in userspace this limit doesn't exist so why make the code
more complicated?

> My second thought was, have you done some timing tests (no I haven't)
> and determined that this causes a noticeable slowdown?

Also, this is not IMO -rc4+ material.

-- Luc
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christopher Li July 29, 2017, 4:16 p.m. UTC | #3
On Sat, Jul 29, 2017 at 9:17 AM, Luc Van Oostenryck
<luc.vanoostenryck@gmail.com> wrote:
>> My first reaction was surprise that you didn't go for the Makefile
>> idea - setting '-Wno-vla' would be the simplest solution. ;-)

Yes, I am convince too. I haven't thought of that.
You can submit a patch for '-Wno-vla'. I will apply it, but most
likely after this release.

>> My second thought was, have you done some timing tests (no I haven't)
>> and determined that this causes a noticeable slowdown?

I did some limited test it is within std on kernel compile. But I am
not very happy
about the stack usage per macro will expand to 8 argument structs regardless
how few arguments used myself. The -Wno-vla is better idea.

> Also, this is not IMO -rc4+ material.

Agree, because it changes the code behavior. Do you mind have the '-Wno-vla'
in -rc5? That should not change any code it generate. I am fine either way.

Chris
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luc Van Oostenryck July 29, 2017, 4:22 p.m. UTC | #4
On Sat, Jul 29, 2017 at 12:16:53PM -0400, Christopher Li wrote:
> On Sat, Jul 29, 2017 at 9:17 AM, Luc Van Oostenryck
> > Also, this is not IMO -rc4+ material.
> 
> Agree, because it changes the code behavior. Do you mind have the '-Wno-vla'
> in -rc5? That should not change any code it generate. I am fine either way.

I don't mind.

-- Luc
--
To unsubscribe from this list: send the line "unsubscribe linux-sparse" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- sparse.chrisl.orig/pre-process.c
+++ sparse.chrisl/pre-process.c
@@ -709,21 +709,30 @@  static int expand(struct token **list, s
  struct ident *expanding = token->ident;
  struct token **tail;
  int nargs = sym->arglist ? sym->arglist->count.normal : 0;
- struct arg *args = NULL;
+#define ARG_LIMIT 8
+ struct arg arg_array[ARG_LIMIT], *args = arg_array;
+ int err = 0;

  if (expanding->tainted) {
  token->pos.noexpand = 1;
  return 1;
  }

- if (nargs > 0)
+ if (nargs >= ARG_LIMIT) {
  args = calloc(nargs, sizeof(*args));
+ if (!args)
+ die("calloc(%d, %lu) failed", nargs, sizeof(*args));
+ }

  if (sym->arglist) {
- if (!match_op(scan_next(&token->next), '('))
- return 1;
- if (!collect_arguments(token->next, sym->arglist, args, token))
- return 1;
+ if (!match_op(scan_next(&token->next), '(')) {
+ err = 1;
+ goto exit;
+ }
+ if (!collect_arguments(token->next, sym->arglist, args, token)) {
+ err = 1;
+ goto exit;
+ }
  expand_arguments(nargs, args);
  }

@@ -741,9 +750,11 @@  static int expand(struct token **list, s
  (*list)->pos.whitespace = token->pos.whitespace;
  *tail = last;

- free(args);
+exit:
+ if (nargs >= ARG_LIMIT)
+ free(args);

- return 0;
+ return err;
 }

 static const char *token_name_sequence(struct token *token, int