These functions (e.g., gr_free()), explicitly dereference the pointer and read the pointee. The /@out@/ comment, which is (almost) analogous to the [[gnu::access(write_only, ...)]] attribute, means that the pointee can be uninitialized, since it won't read it. There's a difference between /@out@/ and the GCC attribute: the attribute doesn't require that the call writes to the pointee, while /@out@/ requires that the pointee be fully initialized after the call, so it _must_ write to it. A guess of why it was used is that these functions are similar to free(3), which does not read the memory it frees, and so one would assume that if it doesn't read, write_only (or equivalents) are good. That's wrong in several ways: - free(3) does not read _nor_ write to the memory, so it would be slightly inappropriate to use write_only with it. It wouldn't be "wrong", but [[gnu::access(none, ...)]] would be more appropriate. - Because /@out@/ requires that the call writes to the pointee, it would be wrong to use it in free(3), which doesn't write to the pointee. - Our functions are similar to free(3) conceptually, but they don't behave like free(3), since they do read the memory (pointee) (and also write to it), and thus they're actually read_write. Link: <https://splint.org/manual/manual.html#undefined> Cc: Serge Hallyn <serge@hallyn.com> Signed-off-by: Alejandro Colomar <alx@kernel.org>
72 lines
1.5 KiB
C
72 lines
1.5 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 1990 - 1994, Julianne Frances Haugh
|
|
* SPDX-FileCopyrightText: 1996 - 2000, Marek Michałkiewicz
|
|
* SPDX-FileCopyrightText: 2001 , Michał Moskal
|
|
* SPDX-FileCopyrightText: 2005 , Tomasz Kłoczko
|
|
* SPDX-FileCopyrightText: 2007 - 2013, Nicolas François
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#ident "$Id$"
|
|
|
|
#include "prototypes.h"
|
|
#include "defines.h"
|
|
#include <shadow.h>
|
|
#include <stdio.h>
|
|
|
|
#include "alloc.h"
|
|
#include "memzero.h"
|
|
#include "shadowio.h"
|
|
|
|
/*@null@*/ /*@only@*/struct spwd *__spw_dup (const struct spwd *spent)
|
|
{
|
|
struct spwd *sp;
|
|
|
|
sp = CALLOC (1, struct spwd);
|
|
if (NULL == sp) {
|
|
return NULL;
|
|
}
|
|
/* The libc might define other fields. They won't be copied. */
|
|
sp->sp_lstchg = spent->sp_lstchg;
|
|
sp->sp_min = spent->sp_min;
|
|
sp->sp_max = spent->sp_max;
|
|
sp->sp_warn = spent->sp_warn;
|
|
sp->sp_inact = spent->sp_inact;
|
|
sp->sp_expire = spent->sp_expire;
|
|
sp->sp_flag = spent->sp_flag;
|
|
/*@-mustfreeonly@*/
|
|
sp->sp_namp = strdup (spent->sp_namp);
|
|
/*@=mustfreeonly@*/
|
|
if (NULL == sp->sp_namp) {
|
|
free(sp);
|
|
return NULL;
|
|
}
|
|
/*@-mustfreeonly@*/
|
|
sp->sp_pwdp = strdup (spent->sp_pwdp);
|
|
/*@=mustfreeonly@*/
|
|
if (NULL == sp->sp_pwdp) {
|
|
free(sp->sp_namp);
|
|
free(sp);
|
|
return NULL;
|
|
}
|
|
|
|
return sp;
|
|
}
|
|
|
|
void
|
|
spw_free(/*@only@*/struct spwd *spent)
|
|
{
|
|
if (spent != NULL) {
|
|
free (spent->sp_namp);
|
|
if (NULL != spent->sp_pwdp) {
|
|
strzero (spent->sp_pwdp);
|
|
free (spent->sp_pwdp);
|
|
}
|
|
free (spent);
|
|
}
|
|
}
|
|
|